Skip to contentSkip to conversation

gcc4 host support

PATCH In review Paul Brook 13 participants 39 messages May 11, 2005 – Jun 20, 2005 1 message not in the archive

lore
Share & tools
lore

Paul Brook

author
#0 lore raw

PATCH 1/1 gcc4 host support

The attached patch adds support for gcc4 x86 and x86_64 hosts.

The main problem with gcc4 is that we can no longer force gcc to place the return from each function at the end of the function.

My solution is to search the function for the "ret" instruction and replace them with a jmp to the next block of code. On RISC targets this would be easy. On x86/x86_64 it's significantly harder because instructions are variable length. This creates two problems:

- Identify the return instruction: Dyngen traces through the code following any branches. When generating a "ret" to exit the translation block, or a "jmp" which will be patched at runtime we generate a privileged instruction instead. dyngen recognises these and replaces them up with the correct value. For simplicity we still require a single ret instruction. This is easy to achieve with the existing FORCE_RET markers.

- Replacing the ret with a jmp: If the ret is not the last instruction we need to replace it with a jmp to the next op. Unfortunately a jmp instruction is 2 or 5 bytes, whereas a ret is just one byte long. To do the replacement we need to move some of the surrounding code out of the way. I've made the FORCE_RET macro insert 4 bytes of nops. This guarantees that we always have 4 bytes we can move without having to redirect any jmps. In almost all cases dyngen can strip these nop instructions, so they never make it into the generated code.

The ppc target code used it's own RETURN macro. I've replaced this with the standard FORCE_RET macro (to get the necessary nops), and changed dyngen so that it can insert nops after each op for debugging purposes.

I've successfully booted the nbench floppy undef i386-sofmmu guest on i686-linux, x86_64-linux and windows hosts with this patch, and verified that arm-user emulation still works. I also compiled op.c with -freorder-block, and it still worked.

On x86-64 the gcc4 compiled qemu runs a few percent faster than with the redhat 3.2.3 system compiler.

On x86 I've had to hack round other bugs (gcc doesn't like doing 64-bit arithmetic with only three 32-bit registers), so is noticably slower. These hacks also slow down gcc3.3 by a similar amount.

Depending on the optimization options used it's also necessary to add FORCE_RET markers to more op.c. I'll submit those separately.

Paul

Index: target-i386/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/op.c,v
retrieving revision 1.37

op.c +10 -0
diff -u -p -r1.37 op.c
@@ -1008,6 +1008,7 @@ void OPPROTO op_aaa(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
+    FORCE_RET();
 }
 
 void OPPROTO op_aas(void)
@@ -1032,6 +1033,7 @@ void OPPROTO op_aas(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
+    FORCE_RET();
 }
 
 void OPPROTO op_daa(void)
@@ -1059,6 +1061,7 @@ void OPPROTO op_daa(void)
     eflags |= parity_table[al]; /* pf */
     eflags |= (al & 0x80); /* sf */
     CC_SRC = eflags;
+    FORCE_RET();
 }
 
 void OPPROTO op_das(void)
@@ -1089,6 +1092,7 @@ void OPPROTO op_das(void)
     eflags |= parity_table[al]; /* pf */
     eflags |= (al & 0x80); /* sf */
     CC_SRC = eflags;
+    FORCE_RET();
 }
 
 /* segment handling */
@@ -1608,6 +1612,7 @@ void OPPROTO op_flds_FT0_A0(void)
 #else
     FT0 = ldfl(A0);
 #endif
+    FORCE_RET();
 }
 
 void OPPROTO op_fldl_FT0_A0(void)
@@ -1618,6 +1623,7 @@ void OPPROTO op_fldl_FT0_A0(void)
 #else
     FT0 = ldfq(A0);
 #endif
+    FORCE_RET();
 }
 
 /* helpers are needed to avoid static constant reference. XXX: find a better way */
@@ -1663,6 +1669,7 @@ void OPPROTO op_fild_FT0_A0(void)
 #else
     FT0 = (CPU86_LDouble)ldsw(A0);
 #endif
+    FORCE_RET();
 }
 
 void OPPROTO op_fildl_FT0_A0(void)
@@ -1673,6 +1680,7 @@ void OPPROTO op_fildl_FT0_A0(void)
 #else
     FT0 = (CPU86_LDouble)((int32_t)ldl(A0));
 #endif
+    FORCE_RET();
 }
 
 void OPPROTO op_fildll_FT0_A0(void)
@@ -1683,6 +1691,7 @@ void OPPROTO op_fildll_FT0_A0(void)
 #else
     FT0 = (CPU86_LDouble)((int64_t)ldq(A0));
 #endif
+    FORCE_RET();
 }
 #endif
 
@@ -2229,6 +2238,7 @@ void OPPROTO op_fldcw_A0(void)
 {
     env->fpuc = lduw(A0);
     update_fp_status();
+    FORCE_RET();
 }
 
 void OPPROTO op_fclex(void)

Index: target-i386/ops_mem.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/ops_mem.h,v retrieving revision 1.6

ops_mem.h +16 -0
diff -u -p -r1.6 ops_mem.h
@@ -1,51 +1,61 @@
 void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = glue(ldub, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = glue(ldsb, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = glue(lduw, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = glue(ldsw, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = (uint32_t)glue(ldl, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(ldub, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(ldsb, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(lduw, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(ldsw, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(ldl, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
@@ -92,6 +102,7 @@ void OPPROTO glue(glue(op_ldq, MEMSUFFIX
     uint64_t *p;
     p = (uint64_t *)((char *)env + PARAM1);
     *p = glue(ldq, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_stq, MEMSUFFIX), _env_A0)(void)
@@ -108,6 +119,7 @@ void OPPROTO glue(glue(op_ldo, MEMSUFFIX
     p = (XMMReg *)((char *)env + PARAM1);
     p->XMM_Q(0) = glue(ldq, MEMSUFFIX)(A0);
     p->XMM_Q(1) = glue(ldq, MEMSUFFIX)(A0 + 8);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void)
@@ -123,21 +135,25 @@ void OPPROTO glue(glue(op_sto, MEMSUFFIX
 void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = (int32_t)glue(ldl, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = (int32_t)glue(ldl, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T0_A0)(void)
 {
     T0 = glue(ldq, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T1_A0)(void)
 {
     T1 = glue(ldq, MEMSUFFIX)(A0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T0_A0)(void)

Index: target-i386/ops_template_mem.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/ops_template_mem.h,v retrieving revision 1.5

ops_template_mem.h +6 -0
diff -u -p -r1.5 ops_template_mem.h
@@ -284,6 +284,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFF
 #endif
     CC_SRC = tmp;
     CC_DST = T0;
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
@@ -326,6 +327,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFF
 #endif
     CC_SRC = tmp;
     CC_DST = T0;
+    FORCE_RET();
 }
 
 
@@ -369,6 +371,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFF
 #endif
     CC_SRC = tmp;
     CC_DST = T0;
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
@@ -407,6 +410,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFF
 #endif
     CC_SRC = tmp;
     CC_DST = T0;
+    FORCE_RET();
 }
 
 
@@ -445,6 +449,7 @@ void OPPROTO glue(glue(op_adc, MEM_SUFFI
     CC_SRC = T1;
     CC_DST = T0;
     CC_OP = CC_OP_ADDB + SHIFT + cf * 4;
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
@@ -458,6 +463,7 @@ void OPPROTO glue(glue(op_sbb, MEM_SUFFI
     CC_SRC = T1;
     CC_DST = T0;
     CC_OP = CC_OP_SUBB + SHIFT + cf * 4;
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)

Index: target-ppc/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-ppc/exec.h,v
retrieving revision 1.10

exec.h +1 -5
diff -u -p -r1.10 exec.h
@@ -33,11 +33,7 @@ register uint32_t T2 asm(AREG3);
 #define FT1 (env->ft1)
 #define FT2 (env->ft2)
 
-#if defined (DEBUG_OP)
-#define RETURN() __asm__ __volatile__("nop");
-#else
-#define RETURN() __asm__ __volatile__("");
-#endif
+#define RETURN() FORCE_RET()
 
 #include "cpu.h"
 #include "exec-all.h"

Index: target-ppc/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-ppc/op.c,v
retrieving revision 1.16

op.c +6 -1
diff -u -p -r1.16 op.c
@@ -489,11 +489,13 @@ PPC_OP(test_ctr)
 PPC_OP(test_ctr_true)
 {
     T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
+    FORCE_RET();
 }
 
 PPC_OP(test_ctr_false)
 {
     T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
+    FORCE_RET();
 }
 
 PPC_OP(test_ctrz)
@@ -504,11 +506,13 @@ PPC_OP(test_ctrz)
 PPC_OP(test_ctrz_true)
 {
     T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
+    FORCE_RET();
 }
 
 PPC_OP(test_ctrz_false)
 {
     T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
+    FORCE_RET();
 }
 
 PPC_OP(test_true)
@@ -1335,9 +1339,10 @@ PPC_OP(fnabs)
 }
 
 /* fneg */
+void do_fneg (void);
 PPC_OP(fneg)
 {
-    FT0 = -FT0;
+    do_fneg();
     RETURN();
 }
 

Index: target-ppc/op_helper.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-ppc/op_helper.c,v retrieving revision 1.12

op_helper.c +5 -0
diff -u -p -r1.12 op_helper.c
@@ -428,6 +428,11 @@ void do_fnabs (void)
     FT0 = p.d;
 }
 
+void do_fneg (void)
+{
+    FT0 = -FT0;
+}
+
 /* Instruction cache invalidation helper */
 #define ICACHE_LINE_SIZE 32
 

Index: target-sparc/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-sparc/exec.h,v retrieving revision 1.10

exec.h +1 -0
diff -u -p -r1.10 exec.h
@@ -34,6 +34,7 @@ void set_cwp(int new_cwp);
 void do_fitos(void);
 void do_fitod(void);
 void do_fabss(void);
+void do_fnegs(void);
 void do_fsqrts(void);
 void do_fsqrtd(void);
 void do_fcmps(void);

Index: target-sparc/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-sparc/op.c,v
retrieving revision 1.15

op.c +1 -1
diff -u -p -r1.15 op.c
@@ -871,7 +871,7 @@ void OPPROTO op_flush_T0(void)
 
 void OPPROTO op_fnegs(void)
 {
-    FT0 = -FT1;
+    do_fnegs();
 }
 
 void OPPROTO op_fabss(void)

Index: target-sparc/op_helper.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-sparc/op_helper.c,v retrieving revision 1.12

op_helper.c +5 -0
diff -u -p -r1.12 op_helper.c
@@ -25,6 +25,11 @@ void do_fabss(void)
     FT0 = float32_abs(FT1);
 }
 
+void do_fnegs(void)
+{
+    FT0 = float32_chs(FT1);
+}
+
 void do_fsqrts(void)
 {
     FT0 = float32_sqrt(FT1, &env->fp_status);

Index: target-sparc/op_mem.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-sparc/op_mem.h,v retrieving revision 1.5

op_mem.h +10 -0
diff -u -p -r1.5 op_mem.h
@@ -3,12 +3,14 @@
 void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void)                           \
 {                                                                             \
     T1 = glue(qp, MEMSUFFIX)(T0);                                     \
+    FORCE_RET();                                                              \
 }
 
 #define SPARC_ST_OP(name, op)                                                 \
 void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void)                           \
 {                                                                             \
     glue(op, MEMSUFFIX)(T0, T1);                                      \
+    FORCE_RET()                                                               \
 }
 
 SPARC_LD_OP(ld, ldl);
@@ -26,12 +28,14 @@ void OPPROTO glue(op_std, MEMSUFFIX)(voi
 {
     glue(stl, MEMSUFFIX)(T0, T1);
     glue(stl, MEMSUFFIX)((T0 + 4), T2);
+    FORCE_RET();
 }
 
 void OPPROTO glue(op_ldstub, MEMSUFFIX)(void)
 {
     T1 = glue(ldub, MEMSUFFIX)(T0);
     glue(stb, MEMSUFFIX)(T0, 0xff);     /* XXX: Should be Atomically */
+    FORCE_RET();
 }
 
 void OPPROTO glue(op_swap, MEMSUFFIX)(void)
@@ -39,33 +43,39 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(vo
     target_ulong tmp = glue(ldl, MEMSUFFIX)(T0);
     glue(stl, MEMSUFFIX)(T0, T1);       /* XXX: Should be Atomically */
     T1 = tmp;
+    FORCE_RET();
 }
 
 void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
 {
     T1 = glue(ldl, MEMSUFFIX)(T0);
     T0 = glue(ldl, MEMSUFFIX)((T0 + 4));
+    FORCE_RET();
 }
 
 /***                         Floating-point store                          ***/
 void OPPROTO glue(op_stf, MEMSUFFIX) (void)
 {
     glue(stfl, MEMSUFFIX)(T0, FT0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(op_stdf, MEMSUFFIX) (void)
 {
     glue(stfq, MEMSUFFIX)(T0, DT0);
+    FORCE_RET();
 }
 
 /***                         Floating-point load                           ***/
 void OPPROTO glue(op_ldf, MEMSUFFIX) (void)
 {
     FT0 = glue(ldfl, MEMSUFFIX)(T0);
+    FORCE_RET();
 }
 
 void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
 {
     DT0 = glue(ldfq, MEMSUFFIX)(T0);
+    FORCE_RET();
 }
 #undef MEMSUFFIX
author
#1 lore raw
Quoted 1 line · Paul Brook

The attached patch adds support for gcc4 x86 and x86_64 hosts.

This time with the correct patch attached.

Paul

Index: dyngen-exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/dyngen-exec.h,v
retrieving revision 1.25

dyngen-exec.h +16 -4
diff -u -p -r1.25 dyngen-exec.h
@@ -155,7 +155,12 @@ extern int printf(const char *, ...);
 #endif
 
 /* force GCC to generate only one epilog at the end of the function */
+#if defined(__i386__) || defined(__x86_64__)
+/* Also add 4 bytes of padding so that we can replace the ret with a jmp.  */
+#define FORCE_RET() asm volatile ("nop;nop;nop;nop");
+#else
 #define FORCE_RET() asm volatile ("");
+#endif
 
 #ifndef OPPROTO
 #define OPPROTO
@@ -205,12 +210,19 @@ extern int __op_jmp0, __op_jmp1, __op_jm
 #endif
 
 #ifdef __i386__
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
+/* Dyngen will replace hlt instructions with a ret instruction.  Inserting a
+   ret directly would confuse dyngen.  */
+#define EXIT_TB() asm volatile ("hlt")
+/* Dyngen will replace cli with 0x9e (jmp). 
+   We generate the offset manually.  */
+#define GOTO_LABEL_PARAM(n) \
+  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
 #endif
 #ifdef __x86_64__
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
+/* The same as i386.  */
+#define EXIT_TB() asm volatile ("hlt")
+#define GOTO_LABEL_PARAM(n) \
+  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
 #endif
 #ifdef __powerpc__
 #define EXIT_TB() asm volatile ("blr")

Index: dyngen.c
===================================================================
RCS file: /cvsroot/qemu/qemu/dyngen.c,v
retrieving revision 1.40

dyngen.c +720 -22

790 lines not on this page · raw message

Index: exec-all.h
===================================================================
RCS file: /cvsroot/qemu/qemu/exec-all.h,v
retrieving revision 1.31

exec-all.h +3 -2
diff -u -p -r1.31 exec-all.h
@@ -335,14 +335,15 @@ do {\
 
 #elif defined(__i386__) && defined(USE_DIRECT_JUMP)
 
-/* we patch the jump instruction directly */
+/* we patch the jump instruction directly.  Use sti in place of the actual
+   jmp instruction so that dyngen can patch in the correct result.  */
 #define GOTO_TB(opname, tbparam, n)\
 do {\
     asm volatile (".section .data\n"\
 		  ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
 		  ".long 1f\n"\
 		  ASM_PREVIOUS_SECTION \
-                  "jmp " ASM_NAME(__op_jmp) #n "\n"\
+                  "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\
 		  "1:\n");\
 } while (0)
 

Index: target-ppc/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-ppc/exec.h,v
retrieving revision 1.10

exec.h +1 -5
diff -u -p -r1.10 exec.h
@@ -33,11 +33,7 @@ register uint32_t T2 asm(AREG3);
 #define FT1 (env->ft1)
 #define FT2 (env->ft2)
 
-#if defined (DEBUG_OP)
-#define RETURN() __asm__ __volatile__("nop");
-#else
-#define RETURN() __asm__ __volatile__("");
-#endif
+#define RETURN() FORCE_RET()
 
 #include "cpu.h"
 #include "exec-all.h"
#2 lore raw
Quoted 4 lines · Paul Brook
Quoted 1 line · Paul Brook

The attached patch adds support for gcc4 x86 and x86_64 hosts.

This time with the correct patch attached.

Hello, I can't build qemu under gcc4.0.0 with your patch and using -O2. I get :
/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h: In function 'op_pshufw_mmx':
/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: error:
unable to find a register to spill in class 'GENERAL_REGS' /home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: error:
this is the insn:
(insn:HI 18 17 19 0 /home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:569 (set (strict_low_part (subreg:HI (reg/v:DI 63 [ r ]) 0))

        (mem/s/j:HI (plus:SI (mult:SI (reg:SI 64)
                    (const_int 2 [0x2]))
                (reg/v/f:SI 59 [ s ])) [0 <variable>._w S2 A16])) 41
{*movstricthi_1} (insn_list:REG_DEP_TRUE 16 (insn_list:REG_DEP_TRUE 12
(insn_list:REG_DEP_TRUE 53 (nil))))
    (expr_list:REG_DEAD (reg:SI 64)
        (nil)))

/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: confused by earlier errors, bailing out

author
#3 lore raw
Quoted 24 lines · Pascal Terjan
Quoted 4 lines · Paul Brook
Quoted 1 line · Paul Brook

The attached patch adds support for gcc4 x86 and x86_64 hosts.

This time with the correct patch attached.

Hello, I can't build qemu under gcc4.0.0 with your patch and using -O2. I get :
/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h: In function 'op_pshufw_mmx':
/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: error:
unable to find a register to spill in class 'GENERAL_REGS' /home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: error:
this is the insn:
(insn:HI 18 17 19 0 /home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:569 (set (strict_low_part (subreg:HI (reg/v:DI 63 [ r ]) 0))

        (mem/s/j:HI (plus:SI (mult:SI (reg:SI 64)
                    (const_int 2 [0x2]))
                (reg/v/f:SI 59 [ s ])) [0 <variable>._w S2 A16])) 41
{*movstricthi_1} (insn_list:REG_DEP_TRUE 16 (insn_list:REG_DEP_TRUE 12
(insn_list:REG_DEP_TRUE 53 (nil))))
    (expr_list:REG_DEAD (reg:SI 64)
        (nil)))
Quoted 2 lines

/home/pterjan/rpm/BUILD/qemu-0.7.0/target-i386/ops_sse.h:574: confused by earlier errors, bailing out

This is a gcc bug. See gcc.gnu.org/PR16185.
Basically gcc doesn't like doing 64-bit arithmetic on a target with only three 32-bit registers (We use the other 4 registers to hold the guest CPU state).

You can hack around this by not holding the guest cpu state in registers, but this incurs a significant speed penalty.

Paul

#4 lore raw
In reply to Paul Brook
Quoted 12 lines · Paul Brook
Quoted 3 lines · Paul Brook

The attached patch adds support for gcc4 x86 and x86_64 hosts.

This time with the correct patch attached.

Paul

In addition to this patch I also needed the attached patch to get MinGW GCC 3.4.1 builds working...

- Filip

dyngen.c +2 -1
@@ -2255,7 +2255,8 @@ void gen_code(const char *name, host_ulo
 
             for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
                 sym_name = get_sym_name(sym);
-                if (strstart(sym_name, "__op_label", &p)) {
+                if (strstart(sym_name, "__op_label", &p) ||
+                    strstart(sym_name, "_op_label", &p)) {
                     uint8_t *ptr;
                     unsigned long offset;
                     
exec-all.h +10 -2
@@ -349,12 +349,20 @@ do {\
 
 #else
 
+#if __GNUC__ == 3 && __GNUC_MINOR__ < 4
+#define UNUSED __attribute__((unused))
+#elif defined(__GNUC__)
+#define UNUSED __attribute__((used))
+#else
+#define UNUSED
+#endif
+
 /* jump to next block operations (more portable code, does not need
    cache flushing, but slower because of indirect jump) */
 #define GOTO_TB(opname, tbparam, n)\
 do {\
-    static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
-    static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
+    static void UNUSED *dummy ## n = &&dummy_label ## n;\
+    static void UNUSED *__op_label ## n = &&label ## n;\
     goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
 label ## n: ;\
 dummy_label ## n: ;\
author
#5 lore raw
Quoted 8 lines

In addition to this patch I also needed the attached patch to get MinGW GCC 3.4.1 builds working...

...
-                if (strstart(sym_name, "__op_label", &p)) {
+                if (strstart(sym_name, "__op_label", &p) ||
+ strstart(sym_name, "_op_label", &p)) {

I'm not sure this is the right fix. Did I miss an ASM_NAME macro somewhere?

Paul

#6 lore raw
Quoted 12 lines · Paul Brook

dyngen.c void gen_code(const char *name, host_ulo · line 2259

Quoted 9 lines

In addition to this patch I also needed the attached patch to get MinGW GCC 3.4.1 builds working...

...

dyngen.c +2 -1
-                if (strstart(sym_name, "__op_label", &p)) {
+                if (strstart(sym_name, "__op_label", &p) ||
+                    strstart(sym_name, "_op_label", &p)) {

I'm not sure this is the right fix. Did I miss an ASM_NAME macro somewhere?

It's not generated by assembler code, but from the C version of GOTO_TB macro. I suppose it's a bug in the particular version of compiler...

- Filip

#13 lore raw
In reply to Paul Brook
Quoted 3 lines · Paul Brook

My solution is to search the function for the "ret" instruction and replace them with a jmp to the next block of code. On RISC targets this would be easy.

About this easy, in fact...

dyngen.c renamed from dyngen.c.x +23 -3
@@ -1996,6 +1996,9 @@ void gen_code(const char *name, host_ulo
     int retpos;
     int exit_addrs[MAX_EXITS];
 #endif
+#if defined(HOST_PPC)
+    uint8_t *blr_addr = NULL;
+#endif
 
     /* Compute exact size excluding prologue and epilogue instructions.
      * Increment start_offset to skip epilogue instructions, then compute
@@ -2018,9 +2021,23 @@ void gen_code(const char *name, host_ulo
         p = (void *)(p_end - 4);
         if (p == p_start)
             error("empty code for %s", name);
-        if (get32((uint32_t *)p) != 0x4e800020)
-            error("blr expected at the end of %s", name);
-        copy_size = p - p_start;
+        if (get32((uint32_t *)p) == 0x4e800020) {
+		copy_size = p - p_start; /* blr at end */
+	} else {
+	    /* Find the blr and note its address so that we 
+	       can emit code to rewrite it to a branch. */
+	    do {
+		p -= 4;
+
+		if (get32((uint32_t *)p) == 0x4e800020) {
+		    blr_addr = p;
+		    copy_size = p_end - p_start;
+		    break;
+		}
+	    } while (p > p_start);
+	    if (p == p_start)
+		error("blr expected in %s", name);
+	}
     }
 #elif defined(HOST_S390)
     {
@@ -2633,6 +2650,9 @@ void gen_code(const char *name, host_ulo
 #else
 #error unsupport object format
 #endif
+		if (blr_addr)
+		    fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = 0x48000000 | %d;\n",
+			    blr_addr - p_start, p_end - blr_addr);
             }
 #elif defined(HOST_S390)
             {
Signature · 1 line
dwmw2
author
#14 lore raw

dyngen.c void gen_code(const char *name, host_ulo · line 2036

Quoted 13 lines · David Woodhouse
Quoted 3 lines · Paul Brook

My solution is to search the function for the "ret" instruction and replace them with a jmp to the next block of code. On RISC targets this would be easy.

About this easy, in fact...
...

dyngen.c renamed from dyngen.c.x +6 -0
+
+		if (get32((uint32_t *)p) == 0x4e800020) {
+		    blr_addr = p;
+		    copy_size = p_end - p_start;
+		    break;
+		}

You probably want to scan the whole function to check there aren't multiple blr instructions, and throw an error if there are.

Other than that it looks ok to me.

Paul

#15 lore raw
Quoted 6 lines · Paul Brook
Quoted 5 lines · David Woodhouse
Quoted 3 lines · Paul Brook

My solution is to search the function for the "ret" instruction and replace them with a jmp to the next block of code. On RISC targets this would be easy.

Quoted 11 lines

dyngen.c void gen_code(const char *name, host_ulo · line 2036

Quoted 8 lines

About this easy, in fact...
...

dyngen.c renamed from dyngen.c.x +6 -0
+
+		if (get32((uint32_t *)p) == 0x4e800020) {
+		    blr_addr = p;
+		    copy_size = p_end - p_start;
+		    break;
+		}

You probably want to scan the whole function to check there aren't multiple blr instructions, and throw an error if there are.

hmm, wouldn't it be much easier to separate compiling from assembling, and do the 'changes' on the assembler files instead?

just an idea ...

best,
Herbert

Quoted 9 lines

Other than that it looks ok to me.

Paul

_______________________________________________
Qemu-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/qemu-devel

#17 lore raw
In reply to Paul Brook
Quoted 2 lines · Paul Brook

For x86 maybe. For ppc it's easier to just scan the binary code. You'd have to write an assembly code parser.

It wouldn't have to know much. I suspect you could do it in awk without much trouble.

Signature · 1 line
dwmw2
author
#16 lore raw
In reply to Herbert Poetzl
Quoted 19 lines · Herbert Poetzl
Quoted 6 lines · Paul Brook
Quoted 5 lines · David Woodhouse
Quoted 3 lines · Paul Brook

My solution is to search the function for the "ret" instruction and replace them with a jmp to the next block of code. On RISC targets this would be easy.

Quoted 11 lines

dyngen.c void gen_code(const char *name, host_ulo · line 2036

Quoted 8 lines

About this easy, in fact...
...

dyngen.c renamed from dyngen.c.x +6 -0
+
+		if (get32((uint32_t *)p) == 0x4e800020) {
+		    blr_addr = p;
+		    copy_size = p_end - p_start;
+		    break;
+		}

You probably want to scan the whole function to check there aren't multiple blr instructions, and throw an error if there are.

Quoted 3 lines

hmm, wouldn't it be much easier to separate compiling from assembling, and do the 'changes' on the assembler files instead?

For x86 maybe. For ppc it's easier to just scan the binary code. You'd have to write an assembly code parser.

Paul

#18 lore raw
In reply to Herbert Poetzl

This all feels wrong in general. The changes should either be adding some facility to gcc which permits QEMU to use it in this way (gcc is an open source project after all, so it's at least a possibility), or we should generate the dynamic code generator once with whatever version of GCC and make that part of the build, perhaps even letting it diverge (i.e. add enhancements/optimizations directly to the generated assembly).

-- John.

author
#19 lore raw
Quoted 3 lines · John Hogerhuis

This all feels wrong in general. The changes should either be adding some facility to gcc which permits QEMU to use it in this way (gcc is an open source project after all, so it's at least a possibility),

Are you willing to write and maintain the gcc patches necessary to do this?

qemu is pretty much the only think that has this particular set of requirelents (the return instruction must be the last instruction in the function). The fact is qemu is abusing the output of gcc in ways that were never guaranteed to work.

Quoted 4 lines

or we should generate the dynamic code generator once with whatever version of GCC and make that part of the build, perhaps even letting it diverge (i.e. add enhancements/optimizations directly to the generated assembly).

IMHO That's not really an option. The whole point of dyngen is to avoid having to write and maintain big chunks of assembly for every single target.

It's been said before that the long-term solution is to [incrementally] remove dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail with Fabrice, and have an almost-working prototype implementation. When I get something that actually works I'll post it to the list for comments.

Paul

#20 lore raw
Quoted 6 lines · Paul Brook

It's been said before that the long-term solution is to [incrementally] remove dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail with Fabrice, and have an almost-working prototype implementation. When I get something that actually works I'll post it to the list for comments.

How feasible would it be to do this as an alternative front end to GCJ's JIT?

Signature · 1 line
dwmw2
author
#21 lore raw
Quoted 10 lines · David Woodhouse
Quoted 6 lines · Paul Brook

It's been said before that the long-term solution is to [incrementally] remove dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail with Fabrice, and have an almost-working prototype implementation. When I get something that actually works I'll post it to the list for comments.

How feasible would it be to do this as an alternative front end to GCJ's JIT?

GCJ doesn't really have a JIT. It has an interpreter, and the ability to compile classes with gcj. I'd expect anything using gcc at runtime would be too slow to be worthwhile.

Paul

#22 lore raw
In reply to David Woodhouse

From: "David Woodhouse"

Quoted 7 lines · Paul Brook
Quoted 3 lines

It's been said before that the long-term solution is to [incrementally] remove dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail

How feasible would it be to do this as an alternative front end to GCJ's JIT?

I am definetly out of my depth here, but... Speaking of GCJ's JIT...

Sometime back, Ian Rogers here brought up the PearColator project at:
http://www.binarytranslator.org/

***
I have been working on an open source Java based PowerPC emulator based around a JVM's optimising compiler. If you have long running server like workloads then I have found the performance is approaching QEMU fast whilst having memory supported by a page based system. However, the system is a lot less sophisticated - booting operating systems and being a generic emulator is a distant reality. I have created a website at
http://www.binarytranslator.org/ or
http://www.cs.man.ac.uk/apt/projects/jamaica/tools/PearColator/ . I'm sure some people would be interested in this and may feel like they want to contribute. I'm happy to oblige and to share with QEMU. Thanks,
***

Looks like he's getting at least some tolerable numbers...

As I said above, I'm out of my depth here. I just thought it was worth bringing this up in case people had forgotten about it.

#23 lore raw
Quoted 5 lines · [email protected] wrote:

I am definetly out of my depth here, but... Speaking of GCJ's JIT...

Sometime back, Ian Rogers here brought up the PearColator project at: http://www.binarytranslator.org/

We're still here and hacking. PearColator and QEMU are quite different projects and we rely on the Jikes RVM code generator - however, that is quite advanced. We can run on other JVMs using reflection, but the performance is so slow to not make that attractive. QEMU is far more developed than we are in terms of running things. I appologize for the now broken links, our main project page is:
http://www.cs.manchester.ac.uk/apt/projects/jamaica/
We're under the CPL as is the Jikes RVM and we're following their typical development cycle of work, publication and then source release. Please contact us for more information.

Regards,

Ian Rogers

author
#24 lore raw
In reply to [email protected]
Quoted 18 lines

I am definetly out of my depth here, but... Speaking of GCJ's JIT...

Sometime back, Ian Rogers here brought up the PearColator project at:
http://www.binarytranslator.org/

***
I have been working on an open source Java based PowerPC emulator based around a JVM's optimising compiler. If you have long running server like workloads then I have found the performance is approaching QEMU fast whilst having memory supported by a page based system. However, the system is a lot less sophisticated - booting operating systems and being a generic emulator is a distant reality. I have created a website at
http://www.binarytranslator.org/ or
http://www.cs.man.ac.uk/apt/projects/jamaica/tools/PearColator/ . I'm sure some people would be interested in this and may feel like they want to contribute. I'm happy to oblige and to share with QEMU. Thanks,
***

Quoted 1 line

Looks like he's getting at least some tolerable numbers...

I know I'd seen something like this before, thanks for reminding me.

There are several issues with PearColator/RVM:

- It's written in java. qemu is written in C, so a lot of porting would be required to get anything working.
- The best benchmark results are half the speed of qemu, and ten times slower appears to be a more typical result.
- I can't see an any way of doing an incremental transition. My code generator coexists with dyngen, allowing a gentle migration away from dyngen.

Paul

#25 lore raw
Quoted 12 lines · Paul Brook

I know I'd seen something like this before, thanks for reminding me.

There are several issues with PearColator/RVM:

- It's written in java. qemu is written in C, so a lot of porting would be required to get anything working.
- The best benchmark results are half the speed of qemu, and ten times slower appears to be a more typical result.
- I can't see an any way of doing an incremental transition. My code generator coexists with dyngen, allowing a gentle migration away from dyngen.

The currently published benchmark results are for PearColator with just an optimizing compiler (worst case in Jikes RVM is over 100 compiler stages). We also emulate a TLB in much the same way as PearPC, so comparing us to QEMU fast isn't fair (we generate in the region of 10 instructions for loads and stores whereas QEMU fast can generate 1). Our best results are for things that sit in dynamic code for a long period of time, which isn't too surprising. We are working on equivalent results to QEMU fast, but our approach is different to that of QEMU and I completely agree that trying to get QEMU/PearColator to co-exist wouldn't be that great.

Regards,

Ian Rogers

#26 lore raw
In reply to Paul Brook
Quoted 5 lines · Paul Brook

It's been said before that the long-term solution is to [incrementally] remove dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail with Fabrice, and have an almost-working prototype implementation. When I get something that actually works I'll post it to the list for comments.

Have you considered the VEX library? I have not tried it yet but it looks promising. However, since it aims at providing a common IR, it can miss certain optimizations related to condition codes (at least as ppc guest).

BTW, since dyngen-based JIT is fast enough both at compile time and at run time, it could be used to gather stats for a higher optimizing JIT (VEX or whatever). e.g. profiling branches in order to optimize hot traces, providing hints for indirect branches, etc.

author
#27 lore raw
Quoted 9 lines · Gwenole Beauchesne
Quoted 7 lines · Paul Brook

It's been said before that the long-term solution is to [incrementally] remove
dyngen altogether, and replace it with a had-written code generator. I've discussed this in a bit more detail with Fabrice, and have an almost-working prototype implementation. When I get something that actually
works I'll post it to the list for comments.

Quoted 4 lines

Have you considered the VEX library? I have not tried it yet but it looks promising. However, since it aims at providing a common IR, it can miss certain optimizations related to condition codes (at least as ppc guest).

Do you have a URL? Neither google nor freshmeat.net turn up anything useful.

Quoted 4 lines

BTW, since dyngen-based JIT is fast enough both at compile time and at run time, it could be used to gather stats for a higher optimizing JIT (VEX or whatever). e.g. profiling branches in order to optimize hot traces, providing hints for indirect branches, etc.

One of the problems with dyngen is it is very fragile, see all the problems trying to make it work with gcc4. My initial goal with a JIT is to replace dyngen.

The big advantage of dyngen is that it is very specialised to qemu. Even though it's about the dumbest JIT implementation you can think of, it gets remarkably good results. Compare it with the Jikes RVM based ppc emulator mentioned recently. The Jikes RVM has ~100 optimizations passes compared to dyngen which has 2 or 3. However the end result is still no better than dyngen because most of that optimization effort is used to remove abstraction that dygen doesn't introduce in the first place.

It would be nice if we could use some sort of portable JIT library, however I think in reality a few qemu specific hacks(most of which we already use with dyngen) and a relatively dumb JIT are going to perform better.

Paul

#28 lore raw
Quoted 1 line · Paul Brook

Do you have a URL? Neither google nor freshmeat.net turn up anything useful.

Sorry, here it is:
<http://svn.valgrind.org/vex/trunk/> (used for valgrind 3.0)
<http://www.valgrind.org/devel/cvs_svn.html>

Quoted 3 lines

It would be nice if we could use some sort of portable JIT library, however I think in reality a few qemu specific hacks(most of which we already use with dyngen) and a relatively dumb JIT are going to perform better.

What about using GNU lightning as an intermediate solution? It has a RISC-style ISA with up to 6 registers exposed. It's "dumb" (no optimization) but it's good at generating code. I think it matches most the "synthetic instruction" approach of dyngen.

#39 lore raw
In reply to Gwenole Beauchesne
Quoted 4 lines · Gwenole Beauchesne

Have you considered the VEX library? I have not tried it yet but it looks promising. However, since it aims at providing a common IR, it can miss certain optimizations related to condition codes (at least as ppc guest).

'VEX' is a poorly googlable term:

http://valgrind.org/devel/cvs_svn.html

svn co svn://svn.valgrind.org/vex/trunk vex

Signature · 2 lines
Jason McMullan <[email protected]>
TimeSys Corporation
author
#29 lore raw
In reply to Gwenole Beauchesne
Quoted 7 lines · Gwenole Beauchesne
Quoted 2 lines · Paul Brook

Do you have a URL? Neither google nor freshmeat.net turn up anything useful.

Sorry, here it is:
<http://svn.valgrind.org/vex/trunk/> (used for valgrind 3.0)
<http://www.valgrind.org/devel/cvs_svn.html>

This looks interesting, the problem is how to get it to cooperate with the dyngen code. We hold some guest CPU state (or at least intermediate state) in host registers.

I guess it depends wether you're willing to throw out dyngen and implement everything in one go. I'm currently trying an incremental approach (as suggested by Fabrice), in which case I think a custom JIT is pretty much the only option.

Quoted 9 lines
Quoted 4 lines

It would be nice if we could use some sort of portable JIT library, however I think in reality a few qemu specific hacks(most of which we already use with dyngen) and a relatively dumb JIT are going to perform better.

What about using GNU lightning as an intermediate solution? It has a RISC-style ISA with up to 6 registers exposed. It's "dumb" (no optimization) but it's good at generating code. I think it matches most the "synthetic instruction" approach of dyngen.

I don't think GNU lightning really gains us much. We'd still have to do the hard bits (optimization, register allocation, assigning stack slots, etc). The actual native code generation (which is what lightning gives you) is only a few hundred lines of code.

Paul

#38 lore raw
In reply to Gwenole Beauchesne

You may also want to look at Dawson Engler's VCODE. Like GNU Lightning it's not been touched in a while.

Ian

Quoted 27 lines · Gwenole Beauchesne
Quoted 3 lines · Paul Brook

Do you have a URL? Neither google nor freshmeat.net turn up anything useful.

Sorry, here it is:
<http://svn.valgrind.org/vex/trunk/> (used for valgrind 3.0)
<http://www.valgrind.org/devel/cvs_svn.html>

Quoted 3 lines

It would be nice if we could use some sort of portable JIT library, however I think in reality a few qemu specific hacks(most of which we already use with dyngen) and a relatively dumb JIT are going to perform better.

What about using GNU lightning as an intermediate solution? It has a RISC-style ISA with up to 6 registers exposed. It's "dumb" (no optimization) but it's good at generating code. I think it matches most the "synthetic instruction" approach of dyngen.

_______________________________________________
Qemu-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/qemu-devel

#30 lore raw
In reply to Paul Brook
Quoted 4 lines · Paul Brook

I don't think GNU lightning really gains us much. We'd still have to do the hard bits (optimization, register allocation, assigning stack slots, etc). The actual native code generation (which is what lightning gives you) is only a few hundred lines of code.

I have the feeling that will apply to most alternatives. The problem is to turn the C code into machine code, right? That is a difficult problem, which is why a C compiler is a complex piece of software. Using a different tool is not going to turn it into a simple problem.

So I think gcc is still the best bet. If the issue with the return point is the only problem, there should be several possible solution (with different performance impact).

Thomas

author
#31 lore raw
Quoted 10 lines · Thomas Steffen
Quoted 4 lines · Paul Brook

I don't think GNU lightning really gains us much. We'd still have to do the hard bits (optimization, register allocation, assigning stack slots, etc). The actual native code generation (which is what lightning gives you) is only a few hundred lines of code.

I have the feeling that will apply to most alternatives. The problem is to turn the C code into machine code, right? That is a difficult problem, which is why a C compiler is a complex piece of software. Using a different tool is not going to turn it into a simple problem.

No. The problem is to turn machine code into (a different form of) machine code. A lot of the complexity in a compiler is involved with with turning the high-level language constructs into simple low-level machine operations.

With qemu we're just translating from one simple form to another, so I'd argue that all you really need is a clever way of papering over the differences between the host and the guest.

What we have now (dyngen) is basically just an assembler. It maps qemu micro ops directly into blocks host code. The only reason dyngen uses gcc is to avoid having to hand write host encodings for all the ops.

Paul

#32 lore raw
Quoted 25 lines · Paul Brook
Quoted 9 lines · Thomas Steffen
Quoted 6 lines · Paul Brook

I don't think GNU lightning really gains us much. We'd still have to do the hard bits (optimization, register allocation, assigning stack slots, etc). The actual native code generation (which is what lightning gives you) is only a few hundred lines of code.

Quoted 6 lines

I have the feeling that will apply to most alternatives. The problem is to turn the C code into machine code, right? That is a difficult problem, which is why a C compiler is a complex piece of software. Using a different tool is not going to turn it into a simple problem.

No. The problem is to turn machine code into (a different form of) machine code. A lot of the complexity in a compiler is involved with with turning the high-level language constructs into simple low-level machine operations.

With qemu we're just translating from one simple form to another, so I'd argue that all you really need is a clever way of papering over the differences between the host and the guest.

What we have now (dyngen) is basically just an assembler. It maps qemu micro ops directly into blocks host code. The only reason dyngen uses gcc is to avoid having to hand write host encodings for all the ops.

Quoted 10 lines

Paul

_______________________________________________
Qemu-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Pardon me for butting in, is any of the host encoding hand written?

Tim

author
#33 lore raw
Quoted 1 line · Tim Walker

Pardon me for butting in, is any of the host encoding hand written?

There is some x86 assembly for the tlb lookup, but everything else is written in C.

Paul

#34 lore raw
In reply to Paul Brook
Quoted 3 lines · Paul Brook

No. The problem is to turn machine code into (a different form of) machine code. A lot of the complexity in a compiler is involved with with turning the high-level language constructs into simple low-level machine operations.

I see your point. I did write a Z80 emulator on an early x86 once. The flags where extremely close, and most commands have a direct correspondency. You just have to decide on a register mapping, and you can start. I wrote short assembler sequences for each command, very much like the targets in qemu. But this is a special case: mapping one architecture on a similar architecture.

Qemu is special an that it avoid both the problem in "papering over the differences", and it avoids the combinatorial explosion of n targets on m hosts. And it does this exactly because it uses C to express machine commands, and not some other machine language. I think you cannot take this away without changing the very nature of qemu.

The reason I care about this is that qemu has achived a lot more than all other similar open source projects together. Look at bochs, or plex86 or valgrind: they are nowhere near the performance of qemu, and they only support x86 targets. So there must be something very ingenious about the design of qemu, and I think it is the combination of gcc and dyngen.

I certainly welcome every possible improvement, but I want to stress how good qemu alread is.

Quoted 3 lines

With qemu we're just translating from one simple form to another, so I'd argue that all you really need is a clever way of papering over the differences between the host and the guest.

So many projects have failed in this direction that I am tempted to assume that this is a flawed approach. Apart from kqemu and VMware, there is not one convincing solution even for the supposedly trivial x86 on x86 case.

Quoted 3 lines

What we have now (dyngen) is basically just an assembler. It maps qemu micro ops directly into blocks host code. The only reason dyngen uses gcc is to avoid having to hand write host encodings for all the ops.

It as also because C avoids the n by m problem.

Thomas

#35 lore raw
Quoted 2 lines · Thomas Steffen

It as also because C avoids the n by m problem.

My point is that you can have your cake and eat it too.

For any given architecture gcc can generate the first approximation by way of dyngen or dyngen + gcc enhancements.

But once you are past that point gcc for a given arch, gcc isn't really going to help you any more. So bring on the hand coding/optimizations. There's no doubt the hand coded stuff would be at least as good as gcc output. And that's because you can always make use of what gcc did if you can't think of anything better.

There's really nothing magic going on we're in any danger of losing. QEMU generates a dynamic code generator dynamically. Clever but lucky hack, in that it really has no business working (yet it does, but the lucky part is why it is going to continue to break).

Short of collusion from the gcc folks, I'm saying that it is no less than the Halting Problem that is staring us in the face here. But no more than that either. Practically speaking, we can probably go on like this indefinitely, it just seems unnecessary to me.

The thing that separates QEMU from other projects like Bochs in my mind is that it dynamically generates code and it has other clever bits like samba and slirp integration. A high level view is that QEMU puts a high priority on usability compared to these other projects.

#36 lore raw
Quoted 3 lines · John Hogerhuis

But once you are past that point gcc for a given arch, gcc isn't really going to help you any more. So bring on the hand coding/optimizations.

And for popular combinations of architectures, such as x86 or PPC on each other, I absolute agree. As in any other routine, you can probably squeeze out a few cycles if you try hard enough.

Quoted 2 lines

And that's because you can always make
use of what gcc did if you can't think of anything better.

So the magic stays with us :-). You need some more complexity in the build process, but I agree that it is a logical improvement.

Thomas

author
#37 lore raw
In reply to John Hogerhuis
Quoted 5 lines · John Hogerhuis

But once you are past that point gcc for a given arch, gcc isn't really going to help you any more. So bring on the hand coding/optimizations. There's no doubt the hand coded stuff would be at least as good as gcc output. And that's because you can always make use of what gcc did if you can't think of anything better.

While I agree with most of what you say, you seem to have misunderstood what I mean by a hand written code generator. I mean teaching qemu how to generate host code directly, not just rewriting bits of op.c in assembly.

Paul

#7 lore raw

[Qemu-devel] Fedora 4 + GCC4 + Qemu WAS: [patch] gcc4 host support

In reply to Paul Brook

Hi,

Fedora Core 4 with gcc4 seems to have some trouble compiling qemu,
even with the below patch attached. EG:
[...snip many signedness errors...]

gcc -Wall -O2 -g -fno-strict-aliasing -fomit-frame-pointer -mpreferred-stack-boundary=2 -falign-functions=0 -fno-gcse -fno-reorder-blocks -fno-optimize-sibling-calls -I. -I/opt/src/qemu-snapshot-2005-06-15_23/target-i386 -I/opt/src/qemu-snapshot-2005-06-15_23 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -I/opt/src/qemu-snapshot-2005-06-15_23/fpu -I/opt/src/qemu-snapshot-2005-06-15_23/slirp -c -o
op.o /opt/src/qemu-snapshot-2005-06-15_23/target-i386/op.c /opt/src/qemu-snapshot-2005-06-15_23/target-i386/ops_template_mem.h: In function ‘op_cmpxchgb_kernel_T0_T1_EAX_cc’:
/opt/src/qemu-snapshot-2005-06-15_23/softmmu_header.h:184: error: can't find a register in class ‘GENERAL_REGS’ while reloading ‘asm’ make[1]: *** [op.o] Error 1
make[1]: Leaving directory `/opt/src/qemu-snapshot-2005-06-15_23/i386-softmmu'
make: *** [all] Error 1

[dixond@unixadmindazfc2 qemu-snapshot-2005-06-15_23]$ gcc --version gcc (GCC) 4.0.0 20050519 (Red Hat 4.0.0-8)

Cheers,
D

Quoted 10 lines · Paul Brook
Quoted 1 line · Paul Brook

The attached patch adds support for gcc4 x86 and x86_64 hosts.

This time with the correct patch attached.

Paul
_______________________________________________
Qemu-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Signature · 1 line
Darryl Dixon <[email protected]>
author
#8 lore raw

Re: [Qemu-devel] Fedora 4 + GCC4 + Qemu WAS: [patch] gcc4 host support

Quoted 5 lines · Darryl Dixon

Hi,

Fedora Core 4 with gcc4 seems to have some trouble compiling qemu,
even with the below patch attached. EG:
[...snip many signedness errors...]

Please read the FAQ. http://www.qemu.org/faq.html

"QEMU does not compile. Why ?

It is likely that you are using GCC 4.x: it is currently not supported by QEMU. You must use GCC 3.x."

Paul

author
#10 lore raw

Re: [Qemu-devel] Fedora 4 + GCC4 + Qemu WAS: [patch] gcc4 host support

In reply to a message not in the archive
Quoted 6 lines · Darryl Dixon

Oh,

Sorry, obviously I badly misunderstood the nature of the patch that
you were posting; I assumed it was to enable Qemu to be compiled with GCC4. That it can't is a pretty big downer; it basically means Qemu is unusable on FC4 :( Ouch. C'est la vie :)

Ah, I see what you mean. I did say in my original post "On x86 I've had to hack round other bugs..." Specifically http://gcc.gnu.org/PR16185

Those hacks are way too ugly for me to want to make them public.

You can get an older version of gcc (3.2.3) on FC4 by installing the compat-gcc packages.

Paul

#11 lore raw

Re: [Qemu-devel] Fedora 4 + GCC4 + Qemu WAS: [patch] gcc4 host support

Quoted 5 lines · Paul Brook
Quoted 4 lines · Darryl Dixon

Sorry, obviously I badly misunderstood the nature of the patch that
you were posting; I assumed it was to enable Qemu to be compiled with GCC4. That it can't is a pretty big downer; it basically means Qemu is unusable on FC4 :( Ouch. C'est la vie :)

Works fine on FC4 PPC :)

Quoted 3 lines

Ah, I see what you mean. I did say in my original post "On x86 I've had to hack round other bugs..." Specifically http://gcc.gnu.org/PR16185

Is that also in Red Hat bugzilla?

Signature · 1 line
dwmw2
#12 lore raw

Re: [Qemu-devel] Fedora 4 + GCC4 + Qemu WAS: [patch] gcc4 host support

In reply to Paul Brook

Aha! Ok, thanks for that. I have compiled Qemu OK now on FC4 with gcc3.2.3 and compiled the accelerator module with gcc4.0 OK. The two seem to work together fine so all is good :)

D

Quoted 18 lines · Paul Brook
Quoted 6 lines · Darryl Dixon

Oh,

Sorry, obviously I badly misunderstood the nature of the patch that
you were posting; I assumed it was to enable Qemu to be compiled with GCC4. That it can't is a pretty big downer; it basically means Qemu is unusable on FC4 :( Ouch. C'est la vie :)

Ah, I see what you mean. I did say in my original post "On x86 I've had to hack round other bugs..." Specifically http://gcc.gnu.org/PR16185

Those hacks are way too ugly for me to want to make them public.

You can get an older version of gcc (3.2.3) on FC4 by installing the compat-gcc packages.

Paul

Signature · 1 line
Darryl Dixon <[email protected]>