ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/cpuopti.c
Revision: 1.3
Committed: 2012-03-30T01:25:46Z (12 years, 8 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +14 -0 lines
Log Message:
Add GPLv2 notices to files from UAE Amiga Emulator, as retrieved from the
COPYING file of uae-0.8.29, retrieved from http://www.amigaemulator.org/
via uae-0.8.29.tar.bz2 (MD5 = 54abbabb5e8580b679c52de019141d61).

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