]> git.sur5r.net Git - cc65/blob - src/cc65/coptsize.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / cc65 / coptsize.c
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
59 typedef struct CallDesc CallDesc;
60 struct 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  */
74 static 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
819 static 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
855 static 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
871 unsigned 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
948 unsigned 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 }