qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [4406] fixed global variable handling with qemu load/ store


From: Fabrice Bellard
Subject: [Qemu-devel] [4406] fixed global variable handling with qemu load/ stores - initial global prologue/epilogue implementation
Date: Sat, 10 May 2008 10:52:06 +0000

Revision: 4406
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4406
Author:   bellard
Date:     2008-05-10 10:52:05 +0000 (Sat, 10 May 2008)

Log Message:
-----------
fixed global variable handling with qemu load/stores - initial global 
prologue/epilogue implementation

Modified Paths:
--------------
    trunk/tcg/i386/tcg-target.c
    trunk/tcg/tcg.c
    trunk/tcg/tcg.h
    trunk/tcg/x86_64/tcg-target.c

Modified: trunk/tcg/i386/tcg-target.c
===================================================================
--- trunk/tcg/i386/tcg-target.c 2008-05-10 10:14:22 UTC (rev 4405)
+++ trunk/tcg/i386/tcg-target.c 2008-05-10 10:52:05 UTC (rev 4406)
@@ -46,6 +46,8 @@
 const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, 
TCG_REG_ECX };
 const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
 
+static uint8_t *tb_ret_addr;
+
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend)
 {
@@ -879,7 +881,8 @@
     switch(opc) {
     case INDEX_op_exit_tb:
         tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
-        tcg_out8(s, 0xc3); /* ret */
+        tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
+        tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
         break;
     case INDEX_op_goto_tb:
         if (s->tb_jmp_offset) {
@@ -1145,6 +1148,53 @@
     { -1 },
 };
 
+static int tcg_target_callee_save_regs[] = {
+    /*    TCG_REG_EBP, */ /* currently used for the global env, so no
+                             need to save */
+    TCG_REG_EBX,
+    TCG_REG_ESI,
+    TCG_REG_EDI,
+};
+
+static inline void tcg_out_push(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, 0x50 + reg);
+}
+
+static inline void tcg_out_pop(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, 0x58 + reg);
+}
+
+/* Generate global QEMU prologue and epilogue code */
+void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int i, frame_size, push_size, stack_addend;
+    
+    /* TB prologue */
+    /* save all callee saved registers */
+    for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_push(s, tcg_target_callee_save_regs[i]);
+    }
+    /* reserve some stack space */
+    push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
+    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & 
+        ~(TCG_TARGET_STACK_ALIGN - 1);
+    stack_addend = frame_size - push_size;
+    tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
+
+    tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */
+    
+    /* TB epilogue */
+    tb_ret_addr = s->code_ptr;
+    tcg_out_addi(s, TCG_REG_ESP, stack_addend);
+    for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+        tcg_out_pop(s, tcg_target_callee_save_regs[i]);
+    }
+    tcg_out8(s, 0xc3); /* ret */
+}
+
 void tcg_target_init(TCGContext *s)
 {
     /* fail safe */

Modified: trunk/tcg/tcg.c
===================================================================
--- trunk/tcg/tcg.c     2008-05-10 10:14:22 UTC (rev 4405)
+++ trunk/tcg/tcg.c     2008-05-10 10:52:05 UTC (rev 4406)
@@ -242,6 +242,13 @@
     }
     
     tcg_target_init(s);
+
+    /* init global prologue and epilogue */
+    s->code_buf = code_gen_prologue;
+    s->code_ptr = s->code_buf;
+    tcg_target_qemu_prologue(s);
+    flush_icache_range((unsigned long)s->code_buf, 
+                       (unsigned long)s->code_ptr);
 }
 
 void tcg_set_frame(TCGContext *s, int reg,
@@ -680,36 +687,57 @@
             nb_oargs = arg >> 16;
             nb_iargs = arg & 0xffff;
             nb_cargs = def->nb_cargs;
-        } else if (c == INDEX_op_nopn) {
-            /* variable number of arguments */
-            nb_cargs = *args;
-            nb_oargs = 0;
-            nb_iargs = 0;
-        } else {
-            nb_oargs = def->nb_oargs;
-            nb_iargs = def->nb_iargs;
-            nb_cargs = def->nb_cargs;
-        }
 
-        k = 0;
-        for(i = 0; i < nb_oargs; i++) {
-            if (k != 0)
-                fprintf(outfile, ",");
-            fprintf(outfile, "%s",
-                    tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
-        }
-        for(i = 0; i < nb_iargs; i++) {
-            if (k != 0)
-                fprintf(outfile, ",");
+            /* function name */
             /* XXX: dump helper name for call */
             fprintf(outfile, "%s",
-                    tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
-        }
-        for(i = 0; i < nb_cargs; i++) {
-            if (k != 0)
+                    tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs + 
nb_iargs - 1]));
+            /* flags */
+            fprintf(outfile, ",$0x%" TCG_PRIlx,
+                    args[nb_oargs + nb_iargs]);
+            /* nb out args */
+            fprintf(outfile, ",$%d", nb_oargs);
+            for(i = 0; i < nb_oargs; i++) {
                 fprintf(outfile, ",");
-            arg = args[k++];
-            fprintf(outfile, "$0x%" TCG_PRIlx, arg);
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i]));
+            }
+            for(i = 0; i < (nb_iargs - 1); i++) {
+                fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[nb_oargs 
+ i]));
+            }
+        } else {
+            if (c == INDEX_op_nopn) {
+                /* variable number of arguments */
+                nb_cargs = *args;
+                nb_oargs = 0;
+                nb_iargs = 0;
+            } else {
+                nb_oargs = def->nb_oargs;
+                nb_iargs = def->nb_iargs;
+                nb_cargs = def->nb_cargs;
+            }
+            
+            k = 0;
+            for(i = 0; i < nb_oargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+            }
+            for(i = 0; i < nb_iargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                fprintf(outfile, "%s",
+                        tcg_get_arg_str_idx(s, buf, sizeof(buf), args[k++]));
+            }
+            for(i = 0; i < nb_cargs; i++) {
+                if (k != 0)
+                    fprintf(outfile, ",");
+                arg = args[k++];
+                fprintf(outfile, "$0x%" TCG_PRIlx, arg);
+            }
         }
         fprintf(outfile, "\n");
         args += nb_iargs + nb_oargs + nb_cargs;
@@ -1027,6 +1055,9 @@
                     /* if end of basic block, update */
                     if (def->flags & TCG_OPF_BB_END) {
                         tcg_la_bb_end(s, dead_temps);
+                    } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
+                        /* globals are live */
+                        memset(dead_temps, 0, s->nb_globals);
                     }
                     
                     /* input args are live */
@@ -1119,9 +1150,7 @@
                 ts->reg != reg) {
                 printf("Inconsistency for register %s:\n", 
                        tcg_target_reg_names[reg]);
-                printf("reg state:\n");
-                dump_regs(s);
-                tcg_abort();
+                goto fail;
             }
         }
     }
@@ -1132,10 +1161,16 @@
             s->reg_to_temp[ts->reg] != k) {
                 printf("Inconsistency for temp %s:\n", 
                        tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
+        fail:
                 printf("reg state:\n");
                 dump_regs(s);
                 tcg_abort();
         }
+        if (ts->val_type == TEMP_VAL_CONST && k < s->nb_globals) {
+            printf("constant forbidden in global %s\n",
+                   tcg_get_arg_str_idx(s, buf, sizeof(buf), k));
+            goto fail;
+        }
     }
 }
 #endif
@@ -1376,13 +1411,26 @@
         }
     }
 
-    /* XXX: permit generic clobber register list ? */ 
     if (def->flags & TCG_OPF_CALL_CLOBBER) {
+        /* XXX: permit generic clobber register list ? */ 
         for(reg = 0; reg < TCG_TARGET_NB_REGS; reg++) {
             if (tcg_regset_test_reg(tcg_target_call_clobber_regs, reg)) {
                 tcg_reg_free(s, reg);
             }
         }
+        /* XXX: for load/store we could do that only for the slow path
+           (i.e. when a memory callback is called) */
+
+        /* store globals and free associated registers (we assume the insn
+           can modify any global. */
+        for(i = 0; i < s->nb_globals; i++) {
+            ts = &s->temps[i];
+            if (!ts->fixed_reg) {
+                if (ts->val_type == TEMP_VAL_REG) {
+                    tcg_reg_free(s, ts->reg);
+                }
+            }
+        }
     }
 
     /* satisfy the output constraints */
@@ -1435,6 +1483,12 @@
     }
 }
 
+#ifdef TCG_TARGET_STACK_GROWSUP
+#define STACK_DIR(x) (-(x))
+#else
+#define STACK_DIR(x) (x)
+#endif
+
 static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
                               int opc, const TCGArg *args,
                               unsigned int dead_iargs)
@@ -1443,7 +1497,7 @@
     TCGArg arg, func_arg;
     TCGTemp *ts;
     tcg_target_long stack_offset, call_stack_size, func_addr;
-    int const_func_arg;
+    int const_func_arg, allocate_args;
     TCGRegSet allocated_regs;
     const TCGArgConstraint *arg_ct;
 
@@ -1464,12 +1518,11 @@
     call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long);
     call_stack_size = (call_stack_size + TCG_TARGET_STACK_ALIGN - 1) & 
         ~(TCG_TARGET_STACK_ALIGN - 1);
-#ifdef TCG_TARGET_STACK_GROWSUP
-    tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
-#else
-    tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
-#endif
-
+    allocate_args = (call_stack_size > TCG_STATIC_CALL_ARGS_SIZE);
+    if (allocate_args) {
+        tcg_out_addi(s, TCG_REG_CALL_STACK, -STACK_DIR(call_stack_size));
+    }
+    /* XXX: on some architectures it does not start at zero */
     stack_offset = 0;
     for(i = nb_regs; i < nb_params; i++) {
         arg = args[nb_oargs + i];
@@ -1491,11 +1544,8 @@
         } else {
             tcg_abort();
         }
-#ifdef TCG_TARGET_STACK_GROWSUP
-        stack_offset -= sizeof(tcg_target_long);
-#else
-        stack_offset += sizeof(tcg_target_long);
-#endif
+        /* XXX: not necessarily in the same order */
+        stack_offset += STACK_DIR(sizeof(tcg_target_long));
     }
     
     /* assign input registers */
@@ -1525,9 +1575,6 @@
     arg_ct = &def->args_ct[0];
     ts = &s->temps[func_arg];
     func_addr = ts->val;
-#ifdef HOST_HPPA
-    func_addr = (tcg_target_long)__canonicalize_funcptr_for_compare((void 
*)func_addr);
-#endif
     const_func_arg = 0;
     if (ts->val_type == TEMP_VAL_MEM) {
         reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
@@ -1586,11 +1633,9 @@
 
     tcg_out_op(s, opc, &func_arg, &const_func_arg);
     
-#ifdef TCG_TARGET_STACK_GROWSUP
-    tcg_out_addi(s, TCG_REG_CALL_STACK, -call_stack_size);
-#else
-    tcg_out_addi(s, TCG_REG_CALL_STACK, call_stack_size);
-#endif
+    if (allocate_args) {
+        tcg_out_addi(s, TCG_REG_CALL_STACK, STACK_DIR(call_stack_size));
+    }
 
     /* assign output registers and emit moves if needed */
     for(i = 0; i < nb_oargs; i++) {
@@ -1672,10 +1717,6 @@
     args = gen_opparam_buf;
     op_index = 0;
 
-#ifdef TCG_TARGET_NEEDS_PROLOGUE
-    tcg_target_prologue(s);
-#endif
-
     for(;;) {
         opc = gen_opc_buf[op_index];
 #ifdef CONFIG_PROFILER

Modified: trunk/tcg/tcg.h
===================================================================
--- trunk/tcg/tcg.h     2008-05-10 10:14:22 UTC (rev 4405)
+++ trunk/tcg/tcg.h     2008-05-10 10:52:05 UTC (rev 4406)
@@ -90,6 +90,10 @@
 
 #define TCG_MAX_TEMPS 512
 
+/* when the size of the arguments of a called function is smaller than
+   this value, they are statically allocated in the TB stack frame */
+#define TCG_STATIC_CALL_ARGS_SIZE 128
+
 typedef int TCGType;
 
 #define TCG_TYPE_I32 0
@@ -285,8 +289,11 @@
 
 #define TCG_OPF_BB_END     0x01 /* instruction defines the end of a basic
                                    block */
-#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers */
-#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects */
+#define TCG_OPF_CALL_CLOBBER 0x02 /* instruction clobbers call registers 
+                                   and potentially update globals. */
+#define TCG_OPF_SIDE_EFFECTS 0x04 /* instruction has side effects : it
+                                     cannot be removed if its output
+                                     are not used */
 
 typedef struct TCGOpDef {
     const char *name;
@@ -305,6 +312,7 @@
 extern TCGOpDef tcg_op_defs[];
 
 void tcg_target_init(TCGContext *s);
+void tcg_target_qemu_prologue(TCGContext *s);
 
 #define tcg_abort() \
 do {\
@@ -358,3 +366,6 @@
 int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
 uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
 uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
+
+extern uint8_t code_gen_prologue[];
+#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void 
*))code_gen_prologue)(tb_ptr)

Modified: trunk/tcg/x86_64/tcg-target.c
===================================================================
--- trunk/tcg/x86_64/tcg-target.c       2008-05-10 10:14:22 UTC (rev 4405)
+++ trunk/tcg/x86_64/tcg-target.c       2008-05-10 10:52:05 UTC (rev 4406)
@@ -73,6 +73,8 @@
     TCG_REG_RDX 
 };
 
+static uint8_t *tb_ret_addr;
+
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend)
 {
@@ -841,7 +843,8 @@
     switch(opc) {
     case INDEX_op_exit_tb:
         tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
-        tcg_out8(s, 0xc3); /* ret */
+        tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
+        tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
         break;
     case INDEX_op_goto_tb:
         if (s->tb_jmp_offset) {
@@ -1129,6 +1132,58 @@
     }
 }
 
+static int tcg_target_callee_save_regs[] = {
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_RBP,
+    TCG_REG_RBX,
+    TCG_REG_R12,
+    TCG_REG_R13,
+    /*    TCG_REG_R14, */ /* currently used for the global env, so no
+                             need to save */
+    TCG_REG_R15,
+};
+
+static inline void tcg_out_push(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0);
+}
+
+static inline void tcg_out_pop(TCGContext *s, int reg)
+{
+    tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0);
+}
+
+/* Generate global QEMU prologue and epilogue code */
+void tcg_target_qemu_prologue(TCGContext *s)
+{
+    int i, frame_size, push_size, stack_addend;
+
+    /* TB prologue */
+    /* save all callee saved registers */
+    for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+        tcg_out_push(s, tcg_target_callee_save_regs[i]);
+
+    }
+    /* reserve some stack space */
+    push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8;
+    frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
+    frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & 
+        ~(TCG_TARGET_STACK_ALIGN - 1);
+    stack_addend = frame_size - push_size;
+    tcg_out_addi(s, TCG_REG_RSP, -stack_addend);
+
+    tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */
+    
+    /* TB epilogue */
+    tb_ret_addr = s->code_ptr;
+    tcg_out_addi(s, TCG_REG_RSP, stack_addend);
+    for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+        tcg_out_pop(s, tcg_target_callee_save_regs[i]);
+    }
+    tcg_out8(s, 0xc3); /* ret */
+}
+
 static const TCGTargetOpDef x86_64_op_defs[] = {
     { INDEX_op_exit_tb, { } },
     { INDEX_op_goto_tb, { } },
@@ -1212,6 +1267,10 @@
 
 void tcg_target_init(TCGContext *s)
 {
+    /* fail safe */
+    if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+        tcg_abort();
+
     tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
     tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
     tcg_regset_set32(tcg_target_call_clobber_regs, 0,
@@ -1227,10 +1286,6 @@
     
     tcg_regset_clear(s->reserved_regs);
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP);
-    /* XXX: will be suppresed when proper global TB entry code will be
-       generated */
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBX);
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_RBP);
     
     tcg_add_target_add_op_defs(x86_64_op_defs);
 }






reply via email to

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