--- uae/src/cpuopti.c 2018/04/24 16:38:53 1.1.1.2 +++ uae/src/cpuopti.c 2018/04/24 16:39:48 1.1.1.3 @@ -15,7 +15,7 @@ struct line { struct line *next, *prev; - int delete; + int delet; char *data; }; @@ -36,48 +36,128 @@ static char * match(struct line *l, cons int len = strlen(m); while (isspace(*str)) str++; - - if (strncmp(str, m, len) != 0) + + if (strncmp(str, m, len) != 0) return NULL; return str + len; } +static int insn_references_reg (struct line *l, char *reg) +{ + if (reg[0] != 'e') { + fprintf(stderr, "Unknown register?!?\n"); + abort(); + } + if (strstr (l->data, reg) != 0) + return 1; + if (strstr (l->data, reg+1) != 0) + return 1; + if (strcmp (reg, "eax") == 0 + && (strstr (l->data, "%al") != 0 || strstr (l->data, "%ah") != 0)) + return 1; + if (strcmp (reg, "ebx") == 0 + && (strstr (l->data, "%bl") != 0 || strstr (l->data, "%bh") != 0)) + return 1; + if (strcmp (reg, "ecx") == 0 + && (strstr (l->data, "%cl") != 0 || strstr (l->data, "%ch") != 0)) + return 1; + if (strcmp (reg, "edx") == 0 + && (strstr (l->data, "%dl") != 0 || strstr (l->data, "%dh") != 0)) + return 1; + return 0; +} + static void do_function(struct func *f) { int pops_at_end = 0; - struct line *l, *fl; + struct line *l, *fl, *l2; char *s, *s2; int in_pop_area = 1; - + f->initial_offset = 0; - + l = f->last_line; fl = f->first_line; if (!match(l,"ret")) oops(); - l = l->prev; - + while (!match(fl, "op_")) fl = fl->next; fl = fl->next; - + + /* Try reordering the insns at the end of the function so that the + * pops are all at the end. */ + l2 = l->prev; + /* Tolerate one stack adjustment */ + if (match (l2, "addl $") && strstr(l2->data, "esp") != 0) + l2 = l2->prev; + for (;;) { + char *forbidden_reg; + struct line *l3, *l4; + + while (match (l2, "popl %")) + l2 = l2->prev; + + l3 = l2; + for (;;) { + forbidden_reg = match (l3, "popl %"); + if (forbidden_reg) + break; + if (l3 == fl) + goto reordered; + /* Jumps and labels put an end to our attempts... */ + if (strstr (l3->data, ".L") != 0) + goto reordered; + /* Likewise accesses to the stack pointer... */ + if (strstr (l3->data, "esp") != 0) + goto reordered; + /* Function calls... */ + if (strstr (l3->data, "call") != 0) + goto reordered; + l3 = l3->prev; + } + if (l3 == l2) + abort(); + for (l4 = l2; l4 != l3; l4 = l4->prev) { + /* The register may not be referenced by any of the insns that we + * move the popl past */ + if (insn_references_reg (l4, forbidden_reg)) + goto reordered; + } + l3->prev->next = l3->next; + l3->next->prev = l3->prev; + l2->next->prev = l3; + l3->next = l2->next; + l2->next = l3; + l3->prev = l2; + } +reordered: + + l = l->prev; + s = match(l, "addl $"); s2 = match(fl, "subl $"); - if (s && s2 && strcmp(s,s2) == 0) { - int v = 0; - while (isdigit(*s)) { - v = v * 10 + (*s) - '0'; - s++; - } - if (strcmp(s, ",%esp") == 0) { - f->initial_offset = v; - l->delete = 2; - fl->delete = 3; - l = l->prev; - fl = fl->next; - } else + if (s && s2) { + if (strcmp(s,s2) == 0) { + int v = 0; + while (isdigit(*s)) { + v = v * 10 + (*s) - '0'; + s++; + } + if (strcmp(s, ",%esp") == 0) { + f->initial_offset = v; + l->delet = 2; + fl->delet = 3; + l = l->prev; + fl = fl->next; + } else + in_pop_area = 0; + } else { + fprintf (stderr, "Stack adjustment not matching\n"); in_pop_area = 0; + } + } while (in_pop_area) { char *popm, *pushm; @@ -85,7 +165,7 @@ static void do_function(struct func *f) pushm = match(fl, "pushl %"); if (popm && pushm && strcmp(pushm, popm) == 0) { pops_at_end++; - fl->delete = l->delete = 1; + fl->delet = l->delet = 1; } else in_pop_area = 0; l = l->prev; @@ -98,9 +178,9 @@ static void do_function(struct func *f) static void output_function(struct func *f) { struct line *l = f->first_line; - + while (l) { - switch (l->delete) { + switch (l->delet) { case 1: break; case 0: @@ -121,18 +201,24 @@ static void output_function(struct func int main(int argc, char **argv) { + FILE *infile = stdin; char tmp[4096]; -#ifdef AMIGA - char *cmd="machdep/cpuopti"; - if(execl(cmd,cmd,NULL)==-1) perror(cmd); - return 10; +#ifdef __mc68000__ + if(system("perl machdep/cpuopti")==-1) { + perror("perl machdep/cpuopti"); + return 10; + } else return 0; #endif + /* For debugging... */ + if (argc == 2) + infile = fopen (argv[1], "r"); + for(;;) { char *s; - - if ((fgets(tmp, 4095, stdin)) == NULL) + + if ((fgets(tmp, 4095, infile)) == NULL) break; s = strchr (tmp, '\n'); @@ -143,7 +229,9 @@ int main(int argc, char **argv) struct line *first_line = NULL, *prev = NULL; struct line **nextp = &first_line; struct func f; - + int nr_rets = 0; + int can_opt = 1; + do { struct line *current; @@ -152,10 +240,17 @@ int main(int argc, char **argv) nextp = ¤t->next; current->prev = prev; prev = current; current->next = NULL; - current->delete = 0; + current->delet = 0; current->data = my_strdup (tmp); + if (match (current, "movl %esp,%ebp") || match (current, "enter")) { + fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data); + can_opt = 0; + } + + if (match (current, "ret")) + nr_rets++; } - if ((fgets(tmp, 4095, stdin)) == NULL) + if ((fgets(tmp, 4095, infile)) == NULL) oops(); s = strchr (tmp, '\n'); if (s != NULL) @@ -165,7 +260,10 @@ int main(int argc, char **argv) f.first_line = first_line; f.last_line = prev; - do_function(&f); + if (nr_rets == 1 && can_opt) + do_function(&f); + /*else + fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/ output_function(&f); } printf("%s\n", tmp);