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

# 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     */
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     }