|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * cpuopti.c - Small optimizer for cpu*.s files ! 5: * Based on work by Tauno Taipaleenmaki ! 6: * ! 7: * Copyright 1996 Bernd Schmidt ! 8: */ ! 9: ! 10: #include <ctype.h> ! 11: ! 12: #include "sysdeps.h" ! 13: /* ! 14: #include "sysconfig.h" ! 15: #include "options.h" ! 16: */ ! 17: ! 18: struct line { ! 19: struct line *next, *prev; ! 20: int delet; ! 21: char *data; ! 22: }; ! 23: ! 24: struct func { ! 25: struct line *first_line, *last_line; ! 26: int initial_offset; ! 27: }; ! 28: ! 29: static void oops(void) ! 30: { ! 31: fprintf(stderr, "Corrupted assembly file!\n"); ! 32: abort(); ! 33: } ! 34: ! 35: /* Not strictly true to definition, as it only checks for match/no match, ! 36: not for ordering */ ! 37: static int mystrncmp(const char* a, const char* b, int len) ! 38: { ! 39: int biswhite=0; ! 40: while (len) { ! 41: if (isspace(*a)) { ! 42: if (!biswhite) { ! 43: biswhite=isspace(*b++); ! 44: while (isspace(*b)) ! 45: b++; ! 46: } ! 47: if (!biswhite) ! 48: return -1; ! 49: } ! 50: else { ! 51: biswhite=0; ! 52: if (*a!=*b++) ! 53: return -1; ! 54: } ! 55: a++; ! 56: len--; ! 57: } ! 58: return 0; ! 59: } ! 60: ! 61: ! 62: static char * match(struct line *l, const char *m) ! 63: { ! 64: char *str = l->data; ! 65: int len = strlen(m); ! 66: while (isspace(*str)) ! 67: str++; ! 68: ! 69: if (mystrncmp(str, m, len) != 0) ! 70: return NULL; ! 71: return str + len; ! 72: } ! 73: ! 74: static int insn_references_reg (struct line *l, char *reg) ! 75: { ! 76: if (reg[0] != 'e') { ! 77: fprintf(stderr, "Unknown register?!?\n"); ! 78: abort(); ! 79: } ! 80: if (strstr (l->data, reg) != 0) ! 81: return 1; ! 82: if (strstr (l->data, reg+1) != 0) ! 83: return 1; ! 84: if (strcmp (reg, "eax") == 0 ! 85: && (strstr (l->data, "%al") != 0 || strstr (l->data, "%ah") != 0)) ! 86: return 1; ! 87: if (strcmp (reg, "ebx") == 0 ! 88: && (strstr (l->data, "%bl") != 0 || strstr (l->data, "%bh") != 0)) ! 89: return 1; ! 90: if (strcmp (reg, "ecx") == 0 ! 91: && (strstr (l->data, "%cl") != 0 || strstr (l->data, "%ch") != 0)) ! 92: return 1; ! 93: if (strcmp (reg, "edx") == 0 ! 94: && (strstr (l->data, "%dl") != 0 || strstr (l->data, "%dh") != 0)) ! 95: return 1; ! 96: return 0; ! 97: } ! 98: ! 99: static void do_function(struct func *f) ! 100: { ! 101: int v; ! 102: int pops_at_end = 0; ! 103: struct line *l, *l1, *fl, *l2; ! 104: char *s, *s2; ! 105: int in_pop_area = 1; ! 106: ! 107: f->initial_offset = 0; ! 108: ! 109: l = f->last_line; ! 110: fl = f->first_line; ! 111: ! 112: if (!match(l,"ret")) ! 113: oops(); ! 114: ! 115: while (!match(fl, "op_")) ! 116: fl = fl->next; ! 117: fl = fl->next; ! 118: ! 119: /* Try reordering the insns at the end of the function so that the ! 120: * pops are all at the end. */ ! 121: l2 = l->prev; ! 122: /* Tolerate one stack adjustment */ ! 123: if (match (l2, "addl $") && strstr(l2->data, "esp") != 0) ! 124: l2 = l2->prev; ! 125: for (;;) { ! 126: char *forbidden_reg; ! 127: struct line *l3, *l4; ! 128: ! 129: while (match (l2, "popl %")) ! 130: l2 = l2->prev; ! 131: ! 132: l3 = l2; ! 133: for (;;) { ! 134: forbidden_reg = match (l3, "popl %"); ! 135: if (forbidden_reg) ! 136: break; ! 137: if (l3 == fl) ! 138: goto reordered; ! 139: /* Jumps and labels put an end to our attempts... */ ! 140: if (strstr (l3->data, ".L") != 0) ! 141: goto reordered; ! 142: /* Likewise accesses to the stack pointer... */ ! 143: if (strstr (l3->data, "esp") != 0) ! 144: goto reordered; ! 145: /* Function calls... */ ! 146: if (strstr (l3->data, "call") != 0) ! 147: goto reordered; ! 148: l3 = l3->prev; ! 149: } ! 150: if (l3 == l2) ! 151: abort(); ! 152: for (l4 = l2; l4 != l3; l4 = l4->prev) { ! 153: /* The register may not be referenced by any of the insns that we ! 154: * move the popl past */ ! 155: if (insn_references_reg (l4, forbidden_reg)) ! 156: goto reordered; ! 157: } ! 158: l3->prev->next = l3->next; ! 159: l3->next->prev = l3->prev; ! 160: l2->next->prev = l3; ! 161: l3->next = l2->next; ! 162: l2->next = l3; ! 163: l3->prev = l2; ! 164: } ! 165: reordered: ! 166: ! 167: l = l->prev; ! 168: ! 169: s = match (l, "addl $"); ! 170: s2 = match (fl, "subl $"); ! 171: ! 172: l1 = l; ! 173: if (s == 0) { ! 174: char *t = match (l, "popl %"); ! 175: if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) { ! 176: s = "4,%esp"; ! 177: l = l->prev; ! 178: t = match (l, "popl %"); ! 179: if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) { ! 180: s = "8,%esp"; ! 181: l = l->prev; ! 182: } ! 183: } ! 184: } else { ! 185: l = l->prev; ! 186: } ! 187: ! 188: if (s && s2) { ! 189: int v = 0; ! 190: if (strcmp (s, s2) != 0) { ! 191: fprintf (stderr, "Stack adjustment not matching.\n"); ! 192: return; ! 193: } ! 194: ! 195: while (isdigit(*s)) { ! 196: v = v * 10 + (*s) - '0'; ! 197: s++; ! 198: } ! 199: ! 200: if (strcmp (s, ",%esp") != 0) { ! 201: fprintf (stderr, "Not adjusting the stack pointer.\n"); ! 202: return; ! 203: } ! 204: f->initial_offset = v; ! 205: fl->delet = 3; ! 206: fl = fl->next; ! 207: l1->delet = 2; ! 208: l1 = l1->prev; ! 209: while (l1 != l) { ! 210: l1->delet = 1; ! 211: l1 = l1->prev; ! 212: } ! 213: } ! 214: ! 215: while (in_pop_area) { ! 216: char *popm, *pushm; ! 217: popm = match (l, "popl %"); ! 218: pushm = match (fl, "pushl %"); ! 219: if (popm && pushm && strcmp(pushm, popm) == 0) { ! 220: pops_at_end++; ! 221: fl->delet = l->delet = 1; ! 222: } else ! 223: in_pop_area = 0; ! 224: l = l->prev; ! 225: fl = fl->next; ! 226: } ! 227: if (f->initial_offset) ! 228: f->initial_offset += 4 * pops_at_end; ! 229: } ! 230: ! 231: static void output_function(struct func *f) ! 232: { ! 233: struct line *l = f->first_line; ! 234: ! 235: while (l) { ! 236: switch (l->delet) { ! 237: case 1: ! 238: break; ! 239: case 0: ! 240: printf("%s\n", l->data); ! 241: break; ! 242: case 2: ! 243: if (f->initial_offset) ! 244: printf("\taddl $%d,%%esp\n", f->initial_offset); ! 245: break; ! 246: case 3: ! 247: if (f->initial_offset) ! 248: printf("\tsubl $%d,%%esp\n", f->initial_offset); ! 249: break; ! 250: } ! 251: l = l->next; ! 252: } ! 253: } ! 254: ! 255: int main(int argc, char **argv) ! 256: { ! 257: FILE *infile = stdin; ! 258: char tmp[4096]; ! 259: ! 260: #ifdef __mc68000__ ! 261: if(system("perl machdep/cpuopti")==-1) { ! 262: perror("perl machdep/cpuopti"); ! 263: return 10; ! 264: } else return 0; ! 265: #endif ! 266: ! 267: /* For debugging... */ ! 268: if (argc == 2) ! 269: infile = fopen (argv[1], "r"); ! 270: ! 271: for(;;) { ! 272: char *s; ! 273: ! 274: if ((fgets(tmp, 4095, infile)) == NULL) ! 275: break; ! 276: ! 277: s = strchr (tmp, '\n'); ! 278: if (s != NULL) ! 279: *s = 0; ! 280: ! 281: if (mystrncmp(tmp, ".globl op_", 10) == 0) { ! 282: struct line *first_line = NULL, *prev = NULL; ! 283: struct line **nextp = &first_line; ! 284: struct func f; ! 285: int nr_rets = 0; ! 286: int can_opt = 1; ! 287: ! 288: do { ! 289: struct line *current; ! 290: ! 291: if (strcmp (tmp, "#APP") != 0 && strcmp (tmp, "#NO_APP") != 0) { ! 292: current = *nextp = (struct line *)malloc(sizeof (struct line)); ! 293: nextp = ¤t->next; ! 294: current->prev = prev; prev = current; ! 295: current->next = NULL; ! 296: current->delet = 0; ! 297: current->data = strdup (tmp); ! 298: if (match (current, "movl %esp,%ebp") || match (current, "enter")) { ! 299: fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data); ! 300: can_opt = 0; ! 301: } ! 302: ! 303: if (match (current, "ret")) ! 304: nr_rets++; ! 305: } ! 306: if ((fgets(tmp, 4095, infile)) == NULL) ! 307: oops(); ! 308: s = strchr (tmp, '\n'); ! 309: if (s != NULL) ! 310: *s = 0; ! 311: } while (strncmp (tmp,".Lfe", 4) != 0); ! 312: ! 313: f.first_line = first_line; ! 314: f.last_line = prev; ! 315: ! 316: if (nr_rets == 1 && can_opt) ! 317: do_function(&f); ! 318: /*else ! 319: fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/ ! 320: output_function(&f); ! 321: } ! 322: printf("%s\n", tmp); ! 323: } ! 324: return 0; ! 325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.