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