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

# User Rev Content
1 cebix 1.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 asvitkine 1.3 *
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 cebix 1.1 */
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 cebix 1.2 exit(1);
45 cebix 1.1 }
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 cebix 1.2 exit(1);
64 cebix 1.1 }
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 cebix 1.2 exit(1);
139 cebix 1.1 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     }