ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/cpuopti.c
Revision: 1.2
Committed: 2001-06-28T21:20:02Z (23 years, 5 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-12, nigel-build-13, nigel-build-16, nigel-build-17, nigel-build-15, snapshot-15012002
Changes since 1.1: +3 -3 lines
Log Message:
video_x.cpp supports resolution switching in windowed mode: the available
resolutions are 512x384, 640x480, 800x600, 1024x768 and 1280x1024 (the prefs
editor has to be updated to reflect this). The resolution selected in the
prefs editor is used as the default, but it can be changed in the Monitors
control panel. So far only tested with direct addressing.

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 cebix 1.2 exit(1);
31 cebix 1.1 }
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 cebix 1.2 exit(1);
50 cebix 1.1 }
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 cebix 1.2 exit(1);
125 cebix 1.1 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     }