1/*****************************************************************************/
2/* */
3/* coptsize.c */
4/* */
5/* Size optimizations */
6/* */
7/* */
8/* */
9/* (C) 2002-2012, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdlib.h>
37
38/* common */
39#include "cpu.h"
40
41/* cc65 */
42#include "codeent.h"
43#include "codeinfo.h"
44#include "coptsize.h"
45#include "reginfo.h"
46
47
48
49/*****************************************************************************/
50/* Data */
51/*****************************************************************************/
52
53
54
55/* Flags for CallDesc */
56#define F_NONE 0x0000U /* No extra flags */
57#define F_SLOWER 0x0001U /* Function call is slower */
58
59typedef struct CallDesc CallDesc;
60struct CallDesc {
61 const char* LongFunc; /* Long function name */
62 RegContents Regs; /* Register contents */
63 unsigned Flags; /* Flags from above */
64 const char* ShortFunc; /* Short function name */
65};
66
67/* Note: The table is sorted. If there is more than one entry with the same
68** name, entries are sorted best match first, so when searching linear for
69** a match, the first one can be used because it is also the best one (or
70** at least none of the following ones are better).
71** Note^2: Ptr1 and Tmp1 aren't evaluated, because runtime routines don't
72** expect parameters here.
73*/
74static const CallDesc CallTable [] = {
75 /* Name A register X register Y register flags replacement */
76 {
77 "addeqysp",
78 {
79 /* A X Y SRegLo */
80 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
81 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
82 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
83 },
84 F_NONE,
85 "addeq0sp"
86 },{
87 "laddeq",
88 {
89 /* A X Y SRegLo */
90 1, 0, UNKNOWN_REGVAL, 0,
91 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
92 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
93 },
94 F_NONE,
95 "laddeq1"
96 },{
97 "laddeq",
98 {
99 /* A X Y SRegLo */
100 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, 0,
101 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
102 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
103 },
104 F_NONE,
105 "laddeqa"
106 },{
107 "laddeqysp",
108 {
109 /* A X Y SRegLo */
110 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
111 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
112 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
113 },
114 F_NONE,
115 "laddeq0sp"
116 },{
117 "ldaxidx",
118 {
119 /* A X Y SRegLo */
120 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL,
121 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
122 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
123 },
124 F_NONE,
125 "ldaxi"
126 },{
127 "ldaxysp",
128 {
129 /* A X Y SRegLo */
130 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL,
131 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
132 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
133 },
134 F_NONE,
135 "ldax0sp"
136 },{
137 "ldeaxidx",
138 {
139 /* A X Y SRegLo */
140 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL,
141 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
142 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
143 },
144 F_NONE,
145 "ldeaxi"
146 },{
147 "ldeaxysp",
148 {
149 /* A X Y SRegLo */
150 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL,
151 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
152 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
153 },
154 F_NONE,
155 "ldeax0sp"
156 },{
157 "leaaxsp",
158 {
159 /* A X Y SRegLo */
160 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
161 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
162 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
163 },
164 F_NONE,
165 "leaa0sp"
166 },{
167 "lsubeq",
168 {
169 /* A X Y SRegLo */
170 1, 0, UNKNOWN_REGVAL, 0,
171 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
172 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
173 },
174 F_NONE,
175 "lsubeq1"
176 },{
177 "lsubeq",
178 {
179 /* A X Y SRegLo */
180 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, 0,
181 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
182 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
183 },
184 F_NONE,
185 "lsubeqa"
186 },{
187 "lsubeqysp",
188 {
189 /* A X Y SRegLo */
190 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
191 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
192 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
193 },
194 F_NONE,
195 "lsubeq0sp"
196 },{
197 "pusha",
198 {
199 /* A X Y SRegLo */
200 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
201 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
202 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
203 },
204 F_SLOWER,
205 "pushc0"
206 },{
207 "pusha",
208 {
209 /* A X Y SRegLo */
210 1, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
211 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
212 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
213 },
214 F_SLOWER,
215 "pushc1"
216 },{
217 "pusha",
218 {
219 /* A X Y SRegLo */
220 2, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
221 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
222 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
223 },
224 F_SLOWER,
225 "pushc2"
226 },{
227 "pushax",
228 {
229 /* A X Y SRegLo */
230 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
231 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
232 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
233 },
234 F_NONE,
235 "push0"
236 },{
237 "pushax",
238 {
239 /* A X Y SRegLo */
240 1, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
241 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
242 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
243 },
244 F_SLOWER,
245 "push1"
246 },{
247 "pushax",
248 {
249 /* A X Y SRegLo */
250 2, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
251 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
252 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
253 },
254 F_SLOWER,
255 "push2"
256 },{
257 "pushax",
258 {
259 /* A X Y SRegLo */
260 3, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
261 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
262 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
263 },
264 F_SLOWER,
265 "push3"
266 },{
267 "pushax",
268 {
269 /* A X Y SRegLo */
270 4, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
271 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
272 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
273 },
274 F_SLOWER,
275 "push4"
276 },{
277 "pushax",
278 {
279 /* A X Y SRegLo */
280 5, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
281 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
282 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
283 },
284 F_SLOWER,
285 "push5"
286 },{
287 "pushax",
288 {
289 /* A X Y SRegLo */
290 6, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
291 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
292 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
293 },
294 F_SLOWER,
295 "push6"
296 },{
297 "pushax",
298 {
299 /* A X Y SRegLo */
300 7, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
301 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
302 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
303 },
304 F_SLOWER,
305 "push7"
306 },{
307 "pushax",
308 {
309 /* A X Y SRegLo */
310 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
311 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
312 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
313 },
314 F_NONE,
315 "pusha0"
316 },{
317 "pushax",
318 {
319 /* A X Y SRegLo */
320 UNKNOWN_REGVAL, 0xFF, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
321 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
322 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
323 },
324 F_SLOWER,
325 "pushaFF"
326 },{
327 "pushaysp",
328 {
329 /* A X Y SRegLo */
330 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
331 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
332 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
333 },
334 F_NONE,
335 "pusha0sp"
336 },{
337 "pusheax",
338 {
339 /* A X Y SRegLo */
340 0, 0, UNKNOWN_REGVAL, 0,
341 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
342 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
343 },
344 F_NONE,
345 "pushl0"
346 },{
347 "pusheax",
348 {
349 /* A X Y SRegLo */
350 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
351 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
352 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
353 },
354 F_NONE,
355 "push0ax"
356 },{
357 "pushwidx",
358 {
359 /* A X Y SRegLo */
360 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 1, UNKNOWN_REGVAL,
361 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
362 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
363 },
364 F_NONE,
365 "pushw"
366 },{
367 "pushwysp",
368 {
369 /* A X Y SRegLo */
370 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 3, UNKNOWN_REGVAL,
371 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
372 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
373 },
374 F_NONE,
375 "pushw0sp"
376 },{
377 "staxysp",
378 {
379 /* A X Y SRegLo */
380 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
381 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
382 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
383 },
384 F_NONE,
385 "stax0sp"
386 },{
387 "steaxysp",
388 {
389 /* A X Y SRegLo */
390 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
391 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
392 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
393 },
394 F_NONE,
395 "steax0sp"
396 },{
397 "subeqysp",
398 {
399 /* A X Y SRegLo */
400 UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL,
401 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
402 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
403 },
404 F_NONE,
405 "subeq0sp"
406 },{
407 "tosaddax",
408 {
409 /* A X Y SRegLo */
410 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
411 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
412 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
413 },
414 F_NONE,
415 "tosadda0"
416 },{
417 "tosaddeax",
418 {
419 /* A X Y SRegLo */
420 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
421 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
422 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
423 },
424 F_NONE,
425 "tosadd0ax"
426 },{
427 "tosandax",
428 {
429 /* A X Y SRegLo */
430 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
431 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
432 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
433 },
434 F_NONE,
435 "tosanda0"
436 },{
437 "tosandeax",
438 {
439 /* A X Y SRegLo */
440 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
441 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
442 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
443 },
444 F_NONE,
445 "tosand0ax"
446 },{
447 "tosdivax",
448 {
449 /* A X Y SRegLo */
450 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
451 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
452 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
453 },
454 F_NONE,
455 "tosdiva0"
456 },{
457 "tosdiveax",
458 {
459 /* A X Y SRegLo */
460 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
461 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
462 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
463 },
464 F_NONE,
465 "tosdiv0ax"
466 },{
467 "toseqax",
468 {
469 /* A X Y SRegLo */
470 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
471 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
472 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
473 },
474 F_NONE,
475 "toseq00"
476 },{
477 "toseqax",
478 {
479 /* A X Y SRegLo */
480 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
481 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
482 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
483 },
484 F_NONE,
485 "toseqa0"
486 },{
487 "tosgeax",
488 {
489 /* A X Y SRegLo */
490 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
491 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
492 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
493 },
494 F_NONE,
495 "tosge00"
496 },{
497 "tosgeax",
498 {
499 /* A X Y SRegLo */
500 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
501 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
502 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
503 },
504 F_NONE,
505 "tosgea0"
506 },{
507 "tosgtax",
508 {
509 /* A X Y SRegLo */
510 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
511 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
512 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
513 },
514 F_NONE,
515 "tosgt00"
516 },{
517 "tosgtax",
518 {
519 /* A X Y SRegLo */
520 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
521 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
522 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
523 },
524 F_NONE,
525 "tosgta0"
526 },{
527 "tosicmp",
528 {
529 /* A X Y SRegLo */
530 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
531 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
532 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
533 },
534 F_NONE,
535 "tosicmp0"
536 },{
537 "tosleax",
538 {
539 /* A X Y SRegLo */
540 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
541 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
542 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
543 },
544 F_NONE,
545 "tosle00"
546 },{
547 "tosleax",
548 {
549 /* A X Y SRegLo */
550 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
551 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
552 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
553 },
554 F_NONE,
555 "toslea0"
556 },{
557 "tosltax",
558 {
559 /* A X Y SRegLo */
560 0, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
561 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
562 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
563 },
564 F_NONE,
565 "toslt00"
566 },{
567 "tosltax",
568 {
569 /* A X Y SRegLo */
570 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
571 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
572 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
573 },
574 F_NONE,
575 "toslta0"
576 },{
577 "tosmodax",
578 {
579 /* A X Y SRegLo */
580 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
581 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
582 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
583 },
584 F_NONE,
585 "tosmoda0"
586 },{
587 "tosmodeax",
588 {
589 /* A X Y SRegLo */
590 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
591 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
592 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
593 },
594 F_NONE,
595 "tosmod0ax"
596 },{
597 "tosmulax",
598 {
599 /* A X Y SRegLo */
600 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
601 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
602 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
603 },
604 F_NONE,
605 "tosmula0"
606 },{
607 "tosmuleax",
608 {
609 /* A X Y SRegLo */
610 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
611 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
612 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
613 },
614 F_NONE,
615 "tosmul0ax"
616 },{
617 "tosneax",
618 {
619 /* A X Y SRegLo */
620 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
621 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
622 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
623 },
624 F_NONE,
625 "tosnea0"
626 },{
627 "tosorax",
628 {
629 /* A X Y SRegLo */
630 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
631 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
632 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
633 },
634 F_NONE,
635 "tosora0"
636 },{
637 "tosoreax",
638 {
639 /* A X Y SRegLo */
640 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
641 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
642 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
643 },
644 F_NONE,
645 "tosor0ax"
646 },{
647 "tosrsubax",
648 {
649 /* A X Y SRegLo */
650 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
651 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
652 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
653 },
654 F_NONE,
655 "tosrsuba0"
656 },{
657 "tosrsubeax",
658 {
659 /* A X Y SRegLo */
660 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
661 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
662 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
663 },
664 F_NONE,
665 "tosrsub0ax"
666 },{
667 "tossubax",
668 {
669 /* A X Y SRegLo */
670 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
671 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
672 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
673 },
674 F_NONE,
675 "tossuba0"
676 },{
677 "tossubeax",
678 {
679 /* A X Y SRegLo */
680 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
681 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
682 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
683 },
684 F_NONE,
685 "tossub0ax"
686 },{
687 "tosudivax",
688 {
689 /* A X Y SRegLo */
690 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
691 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
692 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
693 },
694 F_NONE,
695 "tosudiva0"
696 },{
697 "tosudiveax",
698 {
699 /* A X Y SRegLo */
700 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
701 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
702 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
703 },
704 F_NONE,
705 "tosudiv0ax"
706 },{
707 "tosugeax",
708 {
709 /* A X Y SRegLo */
710 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
711 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
712 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
713 },
714 F_NONE,
715 "tosugea0"
716 },{
717 "tosugtax",
718 {
719 /* A X Y SRegLo */
720 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
721 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
722 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
723 },
724 F_NONE,
725 "tosugta0"
726 },{
727 "tosuleax",
728 {
729 /* A X Y SRegLo */
730 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
731 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
732 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
733 },
734 F_NONE,
735 "tosulea0"
736 },{
737 "tosultax",
738 {
739 /* A X Y SRegLo */
740 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
741 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
742 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
743 },
744 F_NONE,
745 "tosulta0"
746 },{
747 "tosumodax",
748 {
749 /* A X Y SRegLo */
750 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
751 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
752 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
753 },
754 F_NONE,
755 "tosumoda0"
756 },{
757 "tosumodeax",
758 {
759 /* A X Y SRegLo */
760 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
761 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
762 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
763 },
764 F_NONE,
765 "tosumod0ax"
766 },{
767 "tosumulax",
768 {
769 /* A X Y SRegLo */
770 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
771 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
772 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
773 },
774 F_NONE,
775 "tosumula0"
776 },{
777 "tosumuleax",
778 {
779 /* A X Y SRegLo */
780 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
781 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
782 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
783 },
784 F_NONE,
785 "tosumul0ax"
786 },{
787 "tosxorax",
788 {
789 /* A X Y SRegLo */
790 UNKNOWN_REGVAL, 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL,
791 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
792 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
793 },
794 F_NONE,
795 "tosxora0"
796 },{
797 "tosxoreax",
798 {
799 /* A X Y SRegLo */
800 UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL, 0,
801 /* SRegHi Ptr1Lo Ptr1Hi Tmp1 */
802 0, UNKNOWN_REGVAL, UNKNOWN_REGVAL, UNKNOWN_REGVAL
803 },
804 F_NONE,
805 "tosxor0ax"
806 },
807
808};
809#define CALL_COUNT (sizeof(CallTable) / sizeof(CallTable[0]))
810
811
812
813/*****************************************************************************/
814/* Helpers */
815/*****************************************************************************/
816
817
818
819static const CallDesc* FindCall (const char* Name)
820/* Find the function with the given name. Return a pointer to the table entry
821** or NULL if the function was not found.
822*/
823{
824 /* Do a binary search */
825 int First = 0;
826 int Last = CALL_COUNT - 1;
827 int Found = 0;
828
829 while (First <= Last) {
830
831 /* Set current to mid of range */
832 int Current = (Last + First) / 2;
833
834 /* Do a compare */
835 int Result = strcmp (CallTable[Current].LongFunc, Name);
836 if (Result < 0) {
837 First = Current + 1;
838 } else {
839 Last = Current - 1;
840 if (Result == 0) {
841 /* Found. Repeat the procedure until the first of all entries
842 ** with the same name is found.
843 */
844 Found = 1;
845 }
846 }
847 }
848
849 /* Return the first entry if found, or NULL otherwise */
850 return Found? &CallTable[First] : 0;
851}
852
853
854
855static int RegMatch (short Expected, short Actual)
856/* Check for a register match. If Expected has a value, it must be identical
857** to Actual.
858*/
859{
860 return RegValIsUnknown (Expected) || (Expected == Actual);
861}
862
863
864
865/*****************************************************************************/
866/* Code */
867/*****************************************************************************/
868
869
870
871unsigned OptSize1 (CodeSeg* S)
872/* Do size optimization by calling special subroutines that preload registers.
873** This routine does not work standalone, it needs a following register load
874** removal pass.
875*/
876{
877 CodeEntry* E;
878 unsigned Changes = 0;
879 unsigned I;
880
881 /* Are we optimizing for size */
882 int OptForSize = (S->CodeSizeFactor < 100);
883
884 /* Walk over the entries */
885 I = 0;
886 while (I < CS_GetEntryCount (S)) {
887
888 const CallDesc* D;
889
890 /* Get next entry */
891 E = CS_GetEntry (S, I);
892
893 /* Check if it's a subroutine call */
894 if (E->OPC == OP65_JSR && (D = FindCall (E->Arg)) != 0) {
895
896 /* Get input register info for this insn */
897 const RegContents* In = &E->RI->In;
898
899 /* FindCall finds the first entry that matches our function name.
900 ** The names are listed in "best match" order, so search for the
901 ** first one, that fulfills our conditions.
902 */
903 while (1) {
904
905 /* Check the registers and allow slower code only if
906 ** optimizing for size.
907 */
908 if ((OptForSize || (D->Flags & F_SLOWER) == 0) &&
909 RegMatch (D->Regs.RegA, In->RegA) &&
910 RegMatch (D->Regs.RegX, In->RegX) &&
911 RegMatch (D->Regs.RegY, In->RegY) &&
912 RegMatch (D->Regs.SRegLo, In->SRegLo) &&
913 RegMatch (D->Regs.SRegHi, In->SRegHi)) {
914
915 /* Ok, match for all conditions */
916 CodeEntry* X;
917 X = NewCodeEntry (E->OPC, E->AM, D->ShortFunc, 0, E->LI);
918 CS_InsertEntry (S, X, I+1);
919 CS_DelEntry (S, I);
920
921 /* Remember that we had changes */
922 ++Changes;
923
924 /* Done */
925 break;
926 }
927
928 /* Next table entry, bail out if next entry not valid */
929 if (++D >= CallTable + CALL_COUNT ||
930 strcmp (D->LongFunc, E->Arg) != 0) {
931 /* End of table or entries reached */
932 break;
933 }
934 }
935 }
936
937 /* Next entry */
938 ++I;
939
940 }
941
942 /* Return the number of changes made */
943 return Changes;
944}
945
946
947
948unsigned OptSize2 (CodeSeg* S)
949/* Do size optimization by using shorter code sequences, even if this
950** introduces relations between instructions. This step must be one of the
951** last steps, because it makes further work much more difficult.
952*/
953{
954 unsigned Changes = 0;
955 unsigned I;
956
957 /* Walk over the entries */
958 I = 0;
959 while (I < CS_GetEntryCount (S)) {
960
961 /* Get next entry */
962 CodeEntry* E = CS_GetEntry (S, I);
963
964 /* Get the input registers */
965 const RegContents* In = &E->RI->In;
966
967 /* Assume we have no replacement */
968 CodeEntry* X = 0;
969
970 /* Check the instruction */
971 switch (E->OPC) {
972
973 case OP65_LDA:
974 if (CE_IsConstImm (E)) {
975 short Val = (short) E->Num;
976 if (Val == In->RegX) {
977 X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
978 } else if (Val == In->RegY) {
979 X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
980 } else if (RegValIsKnown (In->RegA) && (CPUIsets[CPU] & CPU_ISET_65SC02) != 0) {
981 if (Val == ((In->RegA - 1) & 0xFF)) {
982 X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
983 } else if (Val == ((In->RegA + 1) & 0xFF)) {
984 X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
985 }
986 }
987 }
988 break;
989
990 case OP65_LDX:
991 if (CE_IsConstImm (E)) {
992 short Val = (short) E->Num;
993 if (RegValIsKnown (In->RegX) && Val == ((In->RegX - 1) & 0xFF)) {
994 X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
995 } else if (RegValIsKnown (In->RegX) && Val == ((In->RegX + 1) & 0xFF)) {
996 X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
997 } else if (Val == In->RegA) {
998 X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
999 }
1000 }
1001 break;
1002
1003 case OP65_LDY:
1004 if (CE_IsConstImm (E)) {
1005 short Val = (short) E->Num;
1006 if (RegValIsKnown (In->RegY) && Val == ((In->RegY - 1) & 0xFF)) {
1007 X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
1008 } else if (RegValIsKnown (In->RegY) && Val == ((In->RegY + 1) & 0xFF)) {
1009 X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
1010 } else if (Val == In->RegA) {
1011 X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, E->LI);
1012 }
1013 }
1014 break;
1015
1016 default:
1017 /* Avoid gcc warnings */
1018 break;
1019
1020 }
1021
1022 /* Insert the replacement if we have one */
1023 if (X) {
1024 CS_InsertEntry (S, X, I+1);
1025 CS_DelEntry (S, I);
1026 ++Changes;
1027 }
1028
1029 /* Next entry */
1030 ++I;
1031
1032 }
1033
1034 /* Return the number of changes made */
1035 return Changes;
1036}
1037