|
|
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.