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