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 +#include +#include +#include +#include + +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; iline_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; iline_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;iline_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;jline[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;iline_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;jn; + // 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)