|
|
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: {
1.1.1.4 ! root 72: int v;
1.1 root 73: int pops_at_end = 0;
1.1.1.4 ! root 74: struct line *l, *l1, *fl, *l2;
1.1 root 75: char *s, *s2;
76: int in_pop_area = 1;
1.1.1.3 root 77:
1.1 root 78: f->initial_offset = 0;
1.1.1.3 root 79:
1.1 root 80: l = f->last_line;
81: fl = f->first_line;
82:
83: if (!match(l,"ret"))
84: oops();
1.1.1.3 root 85:
1.1 root 86: while (!match(fl, "op_"))
87: fl = fl->next;
88: fl = fl->next;
1.1.1.3 root 89:
90: /* Try reordering the insns at the end of the function so that the
91: * pops are all at the end. */
92: l2 = l->prev;
93: /* Tolerate one stack adjustment */
94: if (match (l2, "addl $") && strstr(l2->data, "esp") != 0)
95: l2 = l2->prev;
96: for (;;) {
97: char *forbidden_reg;
98: struct line *l3, *l4;
99:
100: while (match (l2, "popl %"))
101: l2 = l2->prev;
102:
103: l3 = l2;
104: for (;;) {
105: forbidden_reg = match (l3, "popl %");
106: if (forbidden_reg)
107: break;
108: if (l3 == fl)
109: goto reordered;
110: /* Jumps and labels put an end to our attempts... */
111: if (strstr (l3->data, ".L") != 0)
112: goto reordered;
113: /* Likewise accesses to the stack pointer... */
114: if (strstr (l3->data, "esp") != 0)
115: goto reordered;
116: /* Function calls... */
117: if (strstr (l3->data, "call") != 0)
118: goto reordered;
119: l3 = l3->prev;
120: }
121: if (l3 == l2)
122: abort();
123: for (l4 = l2; l4 != l3; l4 = l4->prev) {
124: /* The register may not be referenced by any of the insns that we
125: * move the popl past */
126: if (insn_references_reg (l4, forbidden_reg))
127: goto reordered;
128: }
129: l3->prev->next = l3->next;
130: l3->next->prev = l3->prev;
131: l2->next->prev = l3;
132: l3->next = l2->next;
133: l2->next = l3;
134: l3->prev = l2;
135: }
136: reordered:
137:
138: l = l->prev;
139:
1.1.1.4 ! root 140: s = match (l, "addl $");
! 141: s2 = match (fl, "subl $");
! 142:
! 143: l1 = l;
! 144: if (s == 0) {
! 145: char *t = match (l, "popl %");
! 146: if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
! 147: s = "4,%esp";
! 148: l = l->prev;
! 149: t = match (l, "popl %");
! 150: if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) {
! 151: s = "8,%esp";
1.1.1.3 root 152: l = l->prev;
1.1.1.4 ! root 153: }
! 154: }
! 155: } else {
! 156: l = l->prev;
! 157: }
! 158:
! 159: if (s && s2) {
! 160: int v = 0;
! 161: if (strcmp (s, s2) != 0) {
! 162: fprintf (stderr, "Stack adjustment not matching.\n");
! 163: return;
! 164: }
! 165:
! 166: while (isdigit(*s)) {
! 167: v = v * 10 + (*s) - '0';
! 168: s++;
1.1.1.3 root 169: }
170:
1.1.1.4 ! root 171: if (strcmp (s, ",%esp") != 0) {
! 172: fprintf (stderr, "Not adjusting the stack pointer.\n");
! 173: return;
! 174: }
! 175: f->initial_offset = v;
! 176: fl->delet = 3;
! 177: fl = fl->next;
! 178: l1->delet = 2;
! 179: l1 = l1->prev;
! 180: while (l1 != l) {
! 181: l1->delet = 1;
! 182: l1 = l1->prev;
! 183: }
1.1 root 184: }
1.1.1.4 ! root 185:
1.1 root 186: while (in_pop_area) {
187: char *popm, *pushm;
1.1.1.4 ! root 188: popm = match (l, "popl %");
! 189: pushm = match (fl, "pushl %");
1.1 root 190: if (popm && pushm && strcmp(pushm, popm) == 0) {
191: pops_at_end++;
1.1.1.3 root 192: fl->delet = l->delet = 1;
1.1 root 193: } else
194: in_pop_area = 0;
195: l = l->prev;
196: fl = fl->next;
197: }
198: if (f->initial_offset)
199: f->initial_offset += 4 * pops_at_end;
200: }
201:
202: static void output_function(struct func *f)
203: {
204: struct line *l = f->first_line;
1.1.1.3 root 205:
1.1 root 206: while (l) {
1.1.1.3 root 207: switch (l->delet) {
1.1 root 208: case 1:
209: break;
210: case 0:
211: printf("%s\n", l->data);
212: break;
213: case 2:
214: if (f->initial_offset)
215: printf("\taddl $%d,%%esp\n", f->initial_offset);
216: break;
217: case 3:
218: if (f->initial_offset)
219: printf("\tsubl $%d,%%esp\n", f->initial_offset);
220: break;
221: }
222: l = l->next;
223: }
224: }
225:
226: int main(int argc, char **argv)
227: {
1.1.1.3 root 228: FILE *infile = stdin;
1.1 root 229: char tmp[4096];
230:
1.1.1.3 root 231: #ifdef __mc68000__
232: if(system("perl machdep/cpuopti")==-1) {
233: perror("perl machdep/cpuopti");
234: return 10;
235: } else return 0;
1.1.1.2 root 236: #endif
237:
1.1.1.3 root 238: /* For debugging... */
239: if (argc == 2)
240: infile = fopen (argv[1], "r");
241:
1.1 root 242: for(;;) {
243: char *s;
1.1.1.3 root 244:
245: if ((fgets(tmp, 4095, infile)) == NULL)
1.1 root 246: break;
247:
248: s = strchr (tmp, '\n');
249: if (s != NULL)
250: *s = 0;
251:
252: if (strncmp(tmp, ".globl op_", 10) == 0) {
253: struct line *first_line = NULL, *prev = NULL;
254: struct line **nextp = &first_line;
255: struct func f;
1.1.1.3 root 256: int nr_rets = 0;
257: int can_opt = 1;
258:
1.1 root 259: do {
260: struct line *current;
261:
262: if (strcmp (tmp, "#APP") != 0 && strcmp (tmp, "#NO_APP") != 0) {
263: current = *nextp = (struct line *)malloc(sizeof (struct line));
264: nextp = ¤t->next;
265: current->prev = prev; prev = current;
266: current->next = NULL;
1.1.1.3 root 267: current->delet = 0;
1.1 root 268: current->data = my_strdup (tmp);
1.1.1.3 root 269: if (match (current, "movl %esp,%ebp") || match (current, "enter")) {
270: fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data);
271: can_opt = 0;
272: }
273:
274: if (match (current, "ret"))
275: nr_rets++;
1.1 root 276: }
1.1.1.3 root 277: if ((fgets(tmp, 4095, infile)) == NULL)
1.1 root 278: oops();
279: s = strchr (tmp, '\n');
280: if (s != NULL)
281: *s = 0;
282: } while (strncmp (tmp,".Lfe", 4) != 0);
283:
284: f.first_line = first_line;
285: f.last_line = prev;
286:
1.1.1.3 root 287: if (nr_rets == 1 && can_opt)
288: do_function(&f);
289: /*else
290: fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/
1.1 root 291: output_function(&f);
292: }
293: printf("%s\n", tmp);
294: }
295: return 0;
296: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.