ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/cpuopti.c
Revision: 1.1
Committed: 1999-10-03T14:16:26Z (24 years, 8 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

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