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

# 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 exit(1);
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 exit(1);
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 exit(1);
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 }