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