qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [RFC/experimental patch] qemu (x86_64 on x86_64 -no-kqe


From: Anthony Liguori
Subject: Re: [Qemu-devel] [RFC/experimental patch] qemu (x86_64 on x86_64 -no-kqemu) compiles with gcc4 and works
Date: Sat, 24 Mar 2007 15:15:12 -0500
User-agent: Thunderbird 1.5.0.10 (X11/20070307)

Axel Zeuner wrote:
Hi,

Hi Axel,

By adding some GCC4 fixes on top of your patch, I was able to get qemu for i386 (on i386) to compile and run. So far, I've only tested a win2k guest.

The big problem (which pbrook helped me with) was GCC4 freaking out over some stq's. Splitting up the 64bit ops into 32bit ops seemed to address most of the problems.

The tricky thing I still can't figure out is how to get ASM_SOFTMMU working. The problem is GLUE(st, SUFFIX) function. First GCC cannot deal with the register pressure. The problem I can't seem to fix though is that GCC sticks %1 in %esi because we're only using an "r" constraint, not a "q" constraint. This results in the generation of %sib which is an invalid register. However, refactoring the code to not require a "q" constraint doesn't seem to help either.

The attached patch is what I have so far. Some help with people more familiar with gcc asm foo would be appreciated!

Regards,

Anthony Liguori

there were a lot of discussions about compiling qemu with gcc4 or higher. The summary of the discussions were, as I understood, that compiling qemu with gcc4 requires changing the code generation engine of the most of the supported targets. These changes require a lot of work and time.

How about splitting the current static code generation process further? Today gcc produces object code and dyngen adapts it for the purposes of qemu, i.e produces the generation function, patches in parameters ..: gcc -c op.o op.c ;dyngen -o op.h ... op.o . The op_XXX functions generated by gcc may not contain more than one exit
and this exit must be at the end, no not intended jumps to external
functions may occur.

It is possible to split the transformation into the following steps: Generate assembly output from the C-Sources: gcc -S -o op-0.s op.c. Convert the assembly output: cvtasm op.s op-0.s. Assemble the converted assembler sources: as -o op.o op.s. Use dyngen as before: dyngen -o op.h ... op.o. Nothing will change if cvtasm copies only the input to the output, i.e. this additional pass will not break existing code.

A full featured converter (cvtasm) has a lot of dependencies: it has to support all hosts (M) (with all assembler dialects M') and all targets N, i.e. in the worst case one would end with M'x N variants of it, or M x N if one supports only one assembler dialect per host. It is clear, that the number of variants is one of the biggest disadvantages of such an approach.

Now I will focus on x86_64 host and x86_64-softmmu target.
cvtasm has to do the following tasks in this case:
0) convert repXXX; ret to ret only. (Not done yet, x86_64 only, but does not harm). 1) append to all functions, where the last instruction is not a return a ret instruction. 2) add a label to all functions with more than one return before the last return. 3) replace all returns not at the end of a function with an unconditional jump to the generated end label. Avoid touching op_exit_tb here. 4) check all jump instructions if they contain jumps to external labels, replace jumps to external labels with calls to the labels.

The task 0-2 are easy, task 3 may, task 4 is definitely target/host dependent, because there exist intentionally some jumps to external labels, i.e. outside of the function, for instance op_goto_tb. Please correct me, if I am wrong or something is not mentioned above. The attached cvtasm.c allows compiling op.c/op.s/op.o without any disabled optimisations in Makefile.target (patches for Makefile and Makefile.target are attached). The program itself definitely needs a rewrite, is not failsafe and produces to much output on stdout. The macro OP_GOTO_TB from exec-all.h in the general case contains two nice variables and label definitions to force a reference from a variable into the op_goto_tbXXX functions. Unfortunately gcc4 detects that these variables and lables are unused and suppresses their generation, as result dyngen does not generate two lines in op.h: case INDEX_op_goto_tb0: ...
        label_offsets[0] = 8 + (gen_code_ptr - gen_code_buf); // <--
        ...
case INDEX_op_goto_tb1: ... label_offsets[1] = 8 + (gen_code_ptr - gen_code_buf); // <-- ...
and qemu produces a SIGSEGV on the first jump from one buffer to the next.
I was not able to force gcc4 to generate the two variables, therefore I had to replace the general macro with a host dependent one for x86_64 similar to x86 but using the indirect branch method. After the replacement qemu worked when compiled with gcc4.

I made my checks with the following compilers using Debian testing amd64: gcc version 3.4.6 (Debian 3.4.6-5) and gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21).

Please note: These patches work only for x86_64 hosts and x86_64 targets. They will break all other architectures. I did not check i386-softmmu. It works for me.
I apologise for the size of the attachments.

Kind regards
Axel
------------------------------------------------------------------------

_______________________________________________
Qemu-devel mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/qemu-devel

diff -r 83ff8e3c6392 Makefile
--- a/Makefile  Thu Mar 22 12:36:53 2007 +0000
+++ b/Makefile  Sat Mar 24 15:08:16 2007 -0500
@@ -28,7 +28,7 @@ LIBS+=$(AIOLIBS)
 
 all: $(TOOLS) $(DOCS) recurse-all
 
-subdir-%: dyngen$(EXESUF)
+subdir-%: dyngen$(EXESUF) cvtasm$(EXESUF)
        $(MAKE) -C $(subst subdir-,,$@) all
 
 recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
@@ -39,10 +39,14 @@ dyngen$(EXESUF): dyngen.c
 dyngen$(EXESUF): dyngen.c
        $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
 
+cvtasm$(EXESUF): cvtasm.c
+       $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
+
 clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h 
opc-arm.h gen-op-arm.h 
        rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
+       rm -rf cvtasm$(EXESUF)
        $(MAKE) -C tests clean
        for d in $(TARGET_DIRS); do \
        $(MAKE) -C $$d $@ || exit 1 ; \
diff -r 83ff8e3c6392 Makefile.target
--- a/Makefile.target   Thu Mar 22 12:36:53 2007 +0000
+++ b/Makefile.target   Sat Mar 24 15:08:16 2007 -0500
@@ -27,6 +27,7 @@ LIBS=
 LIBS=
 HELPER_CFLAGS=$(CFLAGS)
 DYNGEN=../dyngen$(EXESUF)
+CVTASM=../cvtasm$(EXESUF)
 # user emulator name
 TARGET_ARCH2=$(TARGET_ARCH)
 ifeq ($(TARGET_ARCH),arm)
@@ -78,11 +79,11 @@ cc-option = $(shell if $(CC) $(OP_CFLAGS
 cc-option = $(shell if $(CC) $(OP_CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
               > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
 
-OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "")
-OP_CFLAGS+=$(call cc-option, -fno-gcse, "")
-OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "")
-OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "")
-OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "")
+#OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "")
+#OP_CFLAGS+=$(call cc-option, -fno-gcse, "")
+#OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "")
+#OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "")
+#OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "")
 OP_CFLAGS+=$(call cc-option, -fno-align-labels, "")
 OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "")
 OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, 
-malign-functions=0, ""))
@@ -512,7 +513,12 @@ gen-op.h: op.o $(DYNGEN)
 gen-op.h: op.o $(DYNGEN)
        $(DYNGEN) -g -o $@ $<
 
-op.o: op.c
+op.s: op.c $(CVTASM)
+#      $(CC) $(OP_CFLAGS) $(CPPFLAGS) -E -o op-0.i $<
+       $(CC) $(OP_CFLAGS) $(CPPFLAGS) -fverbose-asm -S -o op-0.s $<
+       $(CVTASM) op-0.s op.s
+
+op.o: op.s
        $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 # HELPER_CFLAGS is used for all the code compiled with static register
@@ -581,7 +587,7 @@ endif
        $(CC) $(CPPFLAGS) -c -o $@ $<
 
 clean:
-       rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o 
fpu/*.o
+       rm -f *.o op-0.s op.s *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o 
slirp/*.o fpu/*.o
 
 install: all 
 ifneq ($(PROGS),)
diff -r 83ff8e3c6392 cpu-all.h
--- a/cpu-all.h Thu Mar 22 12:36:53 2007 +0000
+++ b/cpu-all.h Sat Mar 24 15:08:16 2007 -0500
@@ -339,7 +339,9 @@ static inline void stl_le_p(void *ptr, i
 
 static inline void stq_le_p(void *ptr, uint64_t v)
 {
-    *(uint64_t *)ptr = v;
+    uint8_t *p = ptr;
+    stl_le_p(p, (uint32_t)v);
+    stl_le_p(p + 4, v >> 32);
 }
 
 /* float access */
diff -r 83ff8e3c6392 cvtasm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cvtasm.c  Sat Mar 24 15:08:16 2007 -0500
@@ -0,0 +1,802 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+static void error(const char* fmt, ...) __attribute__((noreturn));
+
+static int cvt_asm(FILE* in, FILE* out);
+
+int main(int argc, char** argv)
+{
+    FILE *in,*out;
+    int r;
+    if ( argc != 3 ) {
+       error("Usage: %s in.s out.s\n", argv[0]);
+    }
+    in = fopen(argv[1],"r");
+    if ( in == NULL ) {
+       error( "%s: could not open %s", argv[1]);
+    }
+    out= fopen(argv[2],"w");
+    if ( out == NULL ) {
+       error("%s: could not open %s", argv[1]);
+    }
+    r = cvt_asm(in,out);
+    fclose(out);
+    fclose(in);
+    return 0;
+}
+
+static void error(const char* fmt, ...)
+{
+    int i;
+    char buf[1024];
+    va_list va;
+    va_start(va,fmt);
+    i=vsnprintf(buf,sizeof(buf),fmt,va);
+    fwrite(buf,i,1,stderr);
+    exit(3);
+}
+
+static void alloc_error() __attribute__((noreturn));
+static void alloc_error()
+{
+    fputs("allocation error\n",stderr);
+    exit(3);
+}
+
+static void* smalloc( size_t s ) 
+{
+    void* p= malloc(s);
+    if ( p == NULL )
+       alloc_error ();
+    return p;
+}
+
+static void* srealloc(void* p, size_t ns)
+{
+    void* np= realloc( p, ns );
+    if ( np== NULL)
+       alloc_error ();
+    return np;
+}
+
+#if defined(__i386__) || defined (__x86_64__)
+#define ARCH_HAS_CVT_ASM 1
+
+#define OP_FUNC_PFX "op_"
+#define ASM_RET "ret"
+#define ASM_ALIGN1 ".p2align"
+#define ASM_ALIGN2 ".align"
+#define ASM_DBG_LOC ".loc"
+#define ASM_DBG_FILE ".file"
+#define ASM_JMP_LABEL1 "__op_gen_label1"
+#define ASM_JMP_LABEL2 "__op_jmp0"
+#define ASM_JMP_LABEL3 "__op_jmp1"
+
+static const char* ASM_JUMP_NAMES[]={
+    "jmp",
+    "ja", "jnbe",
+    "jae", "jnb",
+    "jb", "jnae",
+    "jbe", "jna",
+    "je", "jz",
+    "jg", "jnle",
+    "jge", "jnl",
+    "jl", "jnge",
+    "jle", "jng",
+    "jne", "jnz",
+    "jno",
+    "jnp", "jpo",
+    "jns", "jo",
+    "jp", "jpe",
+    "js",
+    0
+};
+
+static int white(const char* p)
+{
+    return ( (*p == ' ') || (*p == '\t') || (*p == '\r') ||
+            (*p == '\n'));
+       
+}
+
+static int white_or_zero(const char* p)
+{
+    return ( white(p) || (*p == 0));
+}
+
+static const char* eat_white(const char* p)
+{
+    while ( white(p) )
+       ++p;
+    return p;
+}
+
+static const char* eat_non_white(const char* p)
+{
+    while ( !white(p) && (*p != 0) )
+       ++p;
+    return p;
+}
+
+struct line_s {
+    char* l;
+    size_t n;
+    size_t alloc;
+};
+
+static void line_init( struct line_s* s)
+{
+    memset(s,0,sizeof(*s));
+    s->alloc=128;
+    s->l = smalloc(s->alloc);
+    s->l[0]=0;
+}
+
+static void line_destroy( struct line_s* s)
+{
+    free(s->l);
+    s->l =0;
+    s->alloc=0;
+    s->n=0;
+}
+
+static void line_free( struct line_s* s)
+{
+    line_destroy(s);
+    free(s);
+}
+
+static struct line_s* line_copy( const struct line_s* r)
+{
+    struct line_s* l= smalloc(sizeof(*l));
+    l->alloc= r->alloc;
+    l->l= smalloc( l->alloc );
+    l->n = r->n;
+    memcpy(l->l, r->l, r->n+1);
+    return l;
+}
+
+static void line_clear(struct line_s* s)
+{
+    s->n =0;
+    s->l[0] = 0;
+}
+
+static void line_push_char( struct line_s* s, char c)
+{
+    if ( s->n == s->alloc - 1) {
+       size_t a= s->alloc * 2;
+       char* l= srealloc(s->l, a );
+       s->l = l;
+       s->alloc = a;
+    }
+    s->l[s->n] = c;
+    ++s->n;
+    s->l[s->n] = 0;
+}
+
+static struct line_s* line_read(FILE* in)
+{
+    struct line_s* l= smalloc(sizeof(*l));
+    int c;
+    line_init(l);
+    while ( (c=fgetc(in)) != EOF ) {
+       line_push_char(l,c);
+       if ( c == '\n')
+           break;
+    }
+    return l;
+}
+
+static void line_write(const struct line_s* l, FILE* out)
+{
+    fwrite(l->l, l->n, 1, out);
+}
+
+static int line_ptr_in_comment(const struct line_s* l,
+                              const char* p)
+{
+    const char* comment = strchr(l->l,'#');
+    int r= p==0 || ( comment == 0 ? 0 : p >= comment);
+    return r;
+}
+
+static size_t line_label_name( const struct line_s* l, 
+                              char* name, size_t bufsize)
+{
+    const char* colon= strchr(l->l,':');
+    size_t s=0;
+    if (colon != 0) {
+       const char *start= l->l;
+       const char *p;
+       /* eat white spaces */
+       start = eat_white(l->l);
+       /* check for no white spaces between start and colon */
+       p = eat_non_white(start);
+       if ( (p >= colon) && !line_ptr_in_comment(l,p) ) {
+           s= colon - start + 1;
+           if ((name) && (s <= bufsize)) {
+               memcpy(name,start,s-1);
+               name[s-1] = 0;
+           }
+       }
+    }
+    return s;
+}
+
+static int line_is_label( const struct line_s* l)
+{
+    /* asm labels:  white spaces Non#: */
+    int r= line_label_name(l, 0, 0) != 0;
+    return r;
+}
+
+static const char* line_find_token( const struct line_s* l,
+                                   const char* token) {
+    const char* p= strstr(l->l,token);
+    if ( line_ptr_in_comment(l,p) )
+       p=0;
+    return p;
+}
+
+static size_t line_function_start_name( const struct line_s* l,
+                                       char* name, size_t bufsize)
+{
+    const char* type= line_find_token(l,".type");
+    const char* func= line_find_token(l,"@function");
+    size_t s=0;
+    if ( (type != NULL) && (func > type)) {
+       /* extract the function name */
+       const char* typeend=eat_non_white(type);
+       ++typeend;
+       const char* fname=eat_white(typeend);
+       const char* fnend=strchr(fname,',');
+       if ( !line_ptr_in_comment(l,fnend) && (fnend > fname)) {
+           s = fnend -fname + 1;
+           if ((name!=0) && (s <= bufsize)) {
+               memcpy(name,fname,s-1);
+               name[s-1]=0;
+           }
+       }
+    }
+    return s;
+}
+
+static int line_is_function_start(const struct line_s* l)
+{
+    int r=line_function_start_name(l,0,0) !=0;
+    return r;
+}
+
+static size_t line_function_end_name( const struct line_s* l,
+                                     char* name, size_t bufsize)
+{
+    const char* size= line_find_token(l,".size");
+    size_t s=0;
+    if (size != NULL) {
+       /* extract the function name */
+       const char* sizeend=eat_non_white(size);
+       ++sizeend;
+       const char* fname=eat_white(sizeend);
+       const char* fnend=strchr(fname,',');
+       if ( !line_ptr_in_comment(l,fnend) && (fnend > fname)) {
+           s = fnend -fname + 1;
+           if ((name!=0) && (s <= bufsize)) {
+               memcpy(name,fname,s-1);
+               name[s-1]=0;
+           }
+       }
+    }
+    return s;
+}
+
+static size_t line_jxx_target_name( const struct line_s* l, 
+                                   const char* jmpname,
+                                   char* name, size_t bufsize)
+{
+    const char* jmp= line_find_token(l,jmpname);
+    size_t s=0;
+    if ( jmp ) {
+       const char* jmp_end=jmp+strlen(jmpname);
+       if ( white_or_zero(jmp_end) &&
+            ((l->l == jmp) || white(jmp-1))) {
+           const char* start=eat_white(jmp_end);
+           const char* end=eat_non_white (start);
+           if ( !line_ptr_in_comment(l,end) ) {
+               s= end -start +1;
+               if ((name!=0) && (s <= bufsize)) {
+                   memcpy(name,start,s-1);
+                   name[s-1]=0;
+               }
+           }
+       }
+    }
+    return s;
+}
+
+static int line_is_jxx( const struct line_s* l, const char* jmpname)
+{
+    int r= line_jxx_target_name(l,jmpname,0,0)!=0;
+    return r;
+}
+
+static size_t line_jump_target_name(const struct line_s* l, 
+                                   char* name, size_t bufsize)
+{
+    const char** p= ASM_JUMP_NAMES;
+    size_t s=0;
+    while (*p) {
+       size_t k= line_jxx_target_name(l,*p,name,bufsize);
+       if (k ) {
+           s = k;
+           break;
+       }
+       ++p;
+    }
+    return s;
+}
+
+static int line_is_jump( const struct line_s* l)
+{
+    int r=line_jump_target_name(l,0,0)!=0;
+    return r;
+}
+
+
+static size_t line_is_ret(const struct line_s* l)
+{
+    const char* ret= line_find_token(l,ASM_RET);
+    size_t s=0;
+    if ( ret  ) {
+       if ( white_or_zero(ret+strlen(ASM_RET)+1) &&
+            ((l->l == ret) || white(ret-1)))
+           s=1;
+    }
+    return s;
+}
+
+static size_t line_is_align(const struct line_s* l)
+{
+    const char* a= line_find_token(l,ASM_ALIGN1);
+    const char* token = ASM_ALIGN1;
+    size_t s=0;
+    if ( a == 0) {
+       a= line_find_token(l,ASM_ALIGN2);
+       token = ASM_ALIGN2;
+    }
+    if ( a ) {
+       if ( white_or_zero(a+strlen(token)+1) &&
+            ((l->l == a) || white(a-1)))
+           s=1;
+    }
+    return s;
+}
+
+static size_t line_is_dbg(const struct line_s* l)
+{
+    const char* dbg= line_find_token(l,ASM_DBG_LOC);
+    const char* token= ASM_DBG_LOC;
+    size_t s=0;
+    if ( dbg == 0) {
+       dbg = line_find_token(l,ASM_DBG_FILE);
+       token = ASM_DBG_FILE;
+    }
+    if ( dbg  ) {
+       if ( white_or_zero(dbg+strlen(token)+1) &&
+            ((l->l == dbg) || white(dbg-1)))
+           s=1;
+    }
+    return s;
+}
+
+static int line_is_function_end(const struct line_s* l)
+{
+    int r=line_function_end_name(l,0,0) !=0;
+    return r;
+}
+
+struct func_lines_s {
+    /* line pointer, contains allocated pointer to allocated lines */
+    struct line_s** line;
+    /* line count */
+    int n; 
+    /* function name. contains allocated pointer to function name */
+    char* fname;
+};
+
+static void func_lines_init(struct func_lines_s* s)
+{
+    memset(s,0,sizeof(*s));
+}
+
+static struct func_lines_s* func_lines_create()
+{
+    struct func_lines_s* l= smalloc(sizeof(*l));
+    func_lines_init (l);
+    return l;
+}
+
+static struct func_lines_s* func_lines_copy(const struct func_lines_s* r)
+{
+    struct func_lines_s* l= func_lines_create ();
+    int i;
+    l->line = (struct line_s**)smalloc(r->n* sizeof(struct line_s*));
+    l->n = r->n;
+    l->fname = strdup(r->fname);
+    for (i=0; i< l->n;++i) {
+       l->line[i]= line_copy(r->line[i]);
+    }
+    return l;
+}
+
+static void func_lines_destroy(struct func_lines_s* s)
+{
+    if ( s->line) {
+       int i;
+       for ( i = 0; i< s->n; ++i) {
+           line_free(s->line[i]);
+       }
+       free(s->line);
+       s->line =0; // sanity
+    }
+    s->n=0;
+    if ( s->fname ) {
+       free(s->fname);
+       s->fname =0;
+    }
+}
+
+static void func_lines_delete( struct func_lines_s* s)
+{
+    func_lines_destroy(s);
+    free(s);
+}
+
+static void func_lines_append_line( struct func_lines_s* f, 
+                                   const struct line_s* l)
+{
+    struct line_s** line= (struct line_s**)
+       srealloc(f->line, (f->n + 1) * sizeof(l));
+    f->line = line;
+    struct line_s* p= line_copy(l);
+    f->line[f->n]=p;
+    ++f->n;
+       
+    if ( f->fname == 0) {
+       size_t s;
+       if ( (s=line_function_start_name(p,0,0))!=0 ) {
+           f->fname = (char*)smalloc(s);
+           line_function_start_name (p,f->fname,s);
+       }
+    }
+}
+
+static void func_lines_write(const struct func_lines_s* f, FILE* o)
+{
+    if ( f->line ) {
+       int i=0;
+       for (i=0; i< f->n; ++i ) {
+           line_write(f->line[i],o);
+       }
+    }
+}
+
+struct line_info_s {
+    /* jump < 0 line[i] jumps to external function jump[i] == 0 no
+       jump, jump[i] > 0 line of target.  Jumps to local labels
+       may point to the wrong line. Jumps to contents of registers
+       and to magic targets (__op_gen_label1) contain the number
+       of the line itself
+    */
+    int jump;
+    /* ret[i] != 0 line[i] contains an return instruction */
+    int ret;
+    /* line with label ? */
+    int label;
+    /* contains the line an instruction */
+    int instr;
+};
+
+struct transform_s {
+    int name;
+    int ret_cnt;
+    int ret_not_at_end;
+    int external_jumps;
+    struct line_info_s* line_info;
+};
+
+void transform_init( struct transform_s* s, 
+                    const struct func_lines_s* f)
+{
+    int i,j,n;
+    n= f->n;
+    memset(s,0,sizeof(*s));
+    s->line_info=(struct line_info_s*)
+       smalloc(n * sizeof(*s->line_info));
+    memset(s->line_info,0,n*sizeof(*s->line_info));
+
+    /* initialise the static information */
+    for (i = 0; i< n; ++i) {
+       const struct line_s* l= f->line[i];
+       if ( line_is_label (l) )
+           s->line_info[i].label=1;
+       if ( line_is_jump (l) )
+           s->line_info[i].jump=-1;
+       if ( line_is_ret(l) )
+           s->line_info[i].ret=1;
+       if ( !(line_is_function_end (l) ||
+              line_is_function_start (l) ||
+              line_is_label(l) || 
+              line_is_align (l) ||
+              line_is_dbg(l))) {
+           s->line_info[i].instr=1;
+       }
+    }
+    /* now collect the jump target information */
+    for (i=0; i<n; ++i) {
+       if ( s->line_info[i].jump == 0)
+           continue;
+       const struct line_s* l= f->line[i];
+       /* find the corresponding label */
+       size_t js=line_jump_target_name(l,0,0);
+       char* b1= smalloc(js);
+       line_jump_target_name(l,b1,js);
+       /* jumps with address in register are ok */
+       if ( strchr(b1,'%') != 0) {
+           s->line_info[i].jump = i;
+           continue;
+       }
+       /* jumps to __op_gen_label1 are ok */
+       if ( strcmp(b1,ASM_JMP_LABEL1)==0) {
+           s->line_info[i].jump = i;
+           continue;
+       }
+       if ( strcmp(b1,ASM_JMP_LABEL2)==0) {
+           s->line_info[i].jump = i;
+           continue;
+       }
+       if ( strcmp(b1,ASM_JMP_LABEL3)==0) {
+           s->line_info[i].jump = i;
+           continue;
+       }
+       /* js contains the size with trailing 0 */
+       if ((isdigit(b1[0])) && 
+           ((js>1) && 
+            ((b1[js-2]=='f') || (b1[js-2]=='b')))) {
+           // fprintf(stdout, "jmp to local '%s' found\n", b1);
+           b1[js-2]=0;
+       }
+       // fprintf(stdout, "jmp to '%s' found\n", b1);
+       int label_found = 0;
+       for ( j =0 ; j< n && label_found == 0; ++j) {
+           if ( j == i )
+               continue;
+           if ( s->line_info[j].label == 0)
+               continue;
+           const struct line_s* ll= f->line[j];
+           size_t ls=line_label_name(ll,0,0);
+           char* b2= smalloc(ls);
+           line_label_name(ll,b2,ls);
+           // fprintf(stdout, "label '%s'\n", b2);
+           if ( strcmp(b1,b2)==0) {
+               label_found=1;
+               s->line_info[i].jump = j;
+           }
+           free(b2);
+       }
+       free(b1);
+    }
+}
+
+void transform_check( struct transform_s* t,
+                     const struct func_lines_s* f)
+{
+    int i;
+    int n=f->n;
+    for (i=0; i<n; ++i) {
+       const struct line_info_s* info= t->line_info+i;
+       if ( info->ret )
+           ++t->ret_cnt;
+       if ( info->jump < 0) 
+           ++t->external_jumps;
+    }
+    for (i=n-1;i>=0;--i) {
+       const struct line_info_s* info= t->line_info+i;
+       if ( (info->instr != 0) && (info->ret !=0) ) 
+           break;
+       if ( (info->instr != 0) && (info->ret ==0) ) {
+           ++t->ret_not_at_end;
+           break;
+       }
+    }
+}
+
+static void transform_fix ( const struct transform_s* t,
+                           struct func_lines_s* f)
+{
+    int i;
+    int n= f->n;
+    int last_instr=0;
+    // find the last instruction:
+    for (i=n-1;i>=0;--i) {
+       if ( t->line_info[i].instr != 0 ) {
+           last_instr=i;
+           break;
+       }
+    }
+    // produce a label name 
+    char label[128];
+    snprintf(label,sizeof(label),".L%s_exit",f->fname);
+    // replace external jumps with calls
+    for (i=0;i<n;++i) {
+       if (t->line_info[i].jump >= 0) 
+           continue;
+       char jmp_target[512];
+       struct line_s* l= f->line[i];
+       line_jump_target_name(l,jmp_target,sizeof(jmp_target));
+       char call[4096];
+       size_t s;
+       char jmp_ret[512];
+       jmp_ret[0]=0;
+       if ( i != last_instr ) {
+           snprintf(jmp_ret,sizeof(jmp_ret),
+                    "# CVTASM FIX ret after jmp\n"
+                    "\tjmp\t%s\n",label);
+       }
+#if defined (__i386__)
+       s=snprintf(call,sizeof(call),
+                  "# CVTASM FIX jmp --> call\n"
+                  "\tcall\t%s\n%s",
+                  jmp_target,jmp_ret);
+#endif
+#if defined (__x86_64__)
+       s=snprintf(call,sizeof(call),
+                  "# CVTASM FIX jmp --> call\n"
+                  "\tsubq\t$8, %%rsp\n"
+                  "\tcall\t%s\n"
+                  "\taddq\t$8, %%rsp\n%s",
+                  jmp_target,jmp_ret);
+#endif
+       line_clear(l);
+       int j;
+       for (j=0;j<s;++j)
+           line_push_char(l,call[j]);
+    }
+    struct line_s* l= f->line[last_instr];
+    char newlines[4096];
+    size_t s;
+    if ( t->line_info[last_instr].ret !=0 ) {
+       // insert label before the ret.
+       s=snprintf(newlines,sizeof(newlines),
+                  "# CVTASM FIX label before ret \n"
+                  "%s:\n%s",
+                  label, l->l);
+    } else {
+       // insert label after the ret.
+       s=snprintf(newlines,sizeof(newlines),
+                  "%s%s:\n"
+                  "# CVTASM FIX ret at end\n"
+                  "\tret\n",l->l,label);
+    }
+    // convert the line
+    line_clear(l);
+    for (i =0; i< (int)s; ++i)
+       line_push_char(l,newlines[i]);
+    // replace internal rets with jmps to the generated label.
+    for (i=0;i<last_instr;++i) {
+       if ( t->line_info[i].ret == 0)
+           continue;
+       l= f->line[i];
+       line_clear(l);
+       s=snprintf(newlines,sizeof(newlines),
+                  "# CVTASM FIX ret --> jmp to end\n"
+                  "\tjmp %s\n",
+                  label);
+       int j;
+       for (j=0;j<s;++j)
+           line_push_char(l,newlines[j]);
+    }
+}
+
+struct func_lines_s* transform_function ( const struct func_lines_s* f)
+{
+    struct func_lines_s* fn= 0;
+    int n;
+    struct transform_s t;
+    transform_init (&t,f);
+    n=f->n;
+    // do the transformation checks.
+    do {
+       // Name must start with op.
+       if ( strncmp(f->fname,OP_FUNC_PFX,3)!=0) 
+           break;
+       // exit tb has more than one exit
+       if ( strcmp(f->fname,"op_exit_tb")==0)
+           break;
+       // exit tb has more than one exit
+       if ( strcmp(f->fname,"op_exit_tb")==0)
+           break;
+       transform_check (&t,f);
+       if ( t.ret_cnt != 1 )
+           fprintf(stdout, 
+                   "'%s' needs fixing (return count %i)\n", 
+                   f->fname, t.ret_cnt);
+       if ( t.external_jumps != 0 )
+           fprintf(stdout, 
+                   "'%s' needs fixing (external jmps %i)\n", 
+                   f->fname, t.external_jumps);
+       if ( t.ret_not_at_end != 0 )
+           fprintf(stdout, 
+                   "'%s' needs fixing "
+                   "(return not last instruction))\n", 
+                   f->fname);
+       if (t.ret_cnt != 1 || t.ret_not_at_end || 
+           t.external_jumps)  {
+           fn = func_lines_copy (f);
+           transform_fix(&t,fn);
+       }
+    } while (0);
+    return fn;
+}
+
+int cvt_asm( FILE* in, FILE* out)
+{
+    struct line_s* l;
+    struct func_lines_s* f=0;
+    int done =0;
+    do {
+       l = line_read(in);
+       if ( l->n == 0) {
+           if ( f != 0 )
+               error("Not terminated function");
+           done = 1;
+       }
+       if ( f != NULL ) {
+           /* collecting into f */
+           func_lines_append_line (f, l);
+           if ( line_is_function_end (l) ) {
+               /* check for the right function end here */
+               /* Transformation is done here */
+               struct func_lines_s* fn=
+                   transform_function(f);
+               if ( fn ) {
+                   func_lines_write(fn,out);
+                   func_lines_delete(fn);
+               } else {
+                   func_lines_write(f,out);
+               } 
+               func_lines_delete(f);
+               f=0;
+           }
+       } else {
+           /* check if we must collecting into new f */
+           if ( line_is_function_start(l) ) {
+               f= func_lines_create();
+               func_lines_append_line(f,l);
+           } else {
+               /* otherwise copy to output */
+               line_write(l,out);
+           }
+       }
+       free(l);
+    } while ( !done );
+    if ( f )
+       free (f);
+    return 0;
+}
+
+#endif
+
+#if !defined (ARCH_HAS_CVT_ASM)
+int cvt_asm(FILE* in, FILE* out)
+{
+    int c;
+    while ( (c=fgetc(in))!= EOF) 
+       fputc(c,out);
+    return 0;
+}
+#endif
diff -r 83ff8e3c6392 exec-all.h
--- a/exec-all.h        Thu Mar 22 12:36:53 2007 +0000
+++ b/exec-all.h        Sat Mar 24 15:08:16 2007 -0500
@@ -337,6 +337,26 @@ do {\
                  "1:\n");\
 } while (0)
 
+#elif defined (__x86_64__)
+
+/* GCC 4 optimises away the labels after the goto :-( */
+/* This is the main reason for the crashes of qemu if compiled with */
+/* gcc 4 */
+#define GOTO_TB(opname, tbparam, n)                                    \
+do {                                                                   \
+    void* target=(void *)(((TranslationBlock *)tbparam)->tb_next[n]);  \
+    __asm__ __volatile__                                               \
+           ( ".data\n\t"                                               \
+             ".align 8 \n"                                             \
+             ASM_OP_LABEL_NAME(n, opname) ":\n"                        \
+              ".quad 1f\n"                                             \
+              ".previous \n\t"                                         \
+             "jmp *%0\n\t"                                             \
+             "1:\n\t"                                                  \
+             :                                                         \
+             :"a"(target));                                            \
+} while (0)
+
 #else
 
 /* jump to next block operations (more portable code, does not need
diff -r 83ff8e3c6392 target-i386/exec.h
--- a/target-i386/exec.h        Thu Mar 22 12:36:53 2007 +0000
+++ b/target-i386/exec.h        Sat Mar 24 15:08:16 2007 -0500
@@ -231,10 +231,14 @@ static inline void stfq(target_ulong ptr
 {
     union {
         double d;
-        uint64_t i;
+       struct {
+           uint32_t lo;
+           uint32_t hi;
+       } i;
     } u;
     u.d = v;
-    stq(ptr, u.i);
+    stl(ptr, u.i.lo);
+    stl(ptr + 4, u.i.hi);
 }
 
 static inline float ldfl(target_ulong ptr)
@@ -316,7 +320,13 @@ typedef union {
 typedef union {
     long double d;
     struct {
-        unsigned long long lower;
+       union {
+           unsigned long long lower;
+            struct {
+               uint32_t lo;
+               uint32_t hi;
+           } split;
+       };
         unsigned short upper;
     } l;
 } CPU86_LDoubleU;
@@ -444,7 +454,8 @@ static inline void helper_fstt(CPU86_LDo
     CPU86_LDoubleU temp;
     
     temp.d = f;
-    stq(ptr, temp.l.lower);
+    stl(ptr, temp.l.split.lo);
+    stl(ptr + 4, temp.l.split.hi);
     stw(ptr + 8, temp.l.upper);
 }
 
@@ -501,6 +512,7 @@ void helper_hlt(void);
 void helper_hlt(void);
 void helper_monitor(void);
 void helper_mwait(void);
+void helper_pshufw(uint16_t *dst, uint16_t *src, int order);
 
 extern const uint8_t parity_table[256];
 extern const uint8_t rclw_table[32];
diff -r 83ff8e3c6392 target-i386/helper.c
--- a/target-i386/helper.c      Thu Mar 22 12:36:53 2007 +0000
+++ b/target-i386/helper.c      Sat Mar 24 15:08:16 2007 -0500
@@ -3452,8 +3452,10 @@ void helper_fxrstor(target_ulong ptr, in
         nb_xmm_regs = 8 << data64;
         addr = ptr + 0xa0;
         for(i = 0; i < nb_xmm_regs; i++) {
-            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
-            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+            env->xmm_regs[i].XMM_L(0) = ldl(addr);
+            env->xmm_regs[i].XMM_L(1) = ldl(addr + 4);
+            env->xmm_regs[i].XMM_L(2) = ldl(addr + 8);
+            env->xmm_regs[i].XMM_L(3) = ldl(addr + 12);
             addr += 16;
         }
     }
diff -r 83ff8e3c6392 target-i386/helper2.c
--- a/target-i386/helper2.c     Thu Mar 22 12:36:53 2007 +0000
+++ b/target-i386/helper2.c     Sat Mar 24 15:08:16 2007 -0500
@@ -1034,3 +1034,11 @@ void save_native_fp_state(CPUState *env)
     env->native_fp_regs = 0;
 }
 #endif
+
+void helper_pshufw(uint16_t *dst, uint16_t *src, int order)
+{
+    dst[0] = src[order & 3];
+    dst[1] = src[(order >> 2) & 3];
+    dst[2] = src[(order >> 4) & 3];
+    dst[3] = src[(order >> 6) & 3];
+}
diff -r 83ff8e3c6392 target-i386/op.c
--- a/target-i386/op.c  Thu Mar 22 12:36:53 2007 +0000
+++ b/target-i386/op.c  Sat Mar 24 15:08:16 2007 -0500
@@ -18,7 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define ASM_SOFTMMU
+//#define ASM_SOFTMMU
 #include "exec.h"
 
 /* n must be a constant to be efficient */
diff -r 83ff8e3c6392 target-i386/ops_sse.h
--- a/target-i386/ops_sse.h     Thu Mar 22 12:36:53 2007 +0000
+++ b/target-i386/ops_sse.h     Sat Mar 24 15:08:16 2007 -0500
@@ -580,16 +580,9 @@ void OPPROTO glue(op_movq_T0_mm, SUFFIX)
 #if SHIFT == 0
 void OPPROTO glue(op_pshufw, SUFFIX) (void)
 {
-    Reg r, *d, *s;
-    int order;
-    d = (Reg *)((char *)env + PARAM1);
-    s = (Reg *)((char *)env + PARAM2);
-    order = PARAM3;
-    r.W(0) = s->W(order & 3);
-    r.W(1) = s->W((order >> 2) & 3);
-    r.W(2) = s->W((order >> 4) & 3);
-    r.W(3) = s->W((order >> 6) & 3);
-    *d = r;
+    helper_pshufw((uint16_t *)((char *)env + PARAM1),
+                 (uint16_t *)((char *)env + PARAM2),
+                 PARAM3);
 }
 #else
 void OPPROTO op_shufps(void)

reply via email to

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