]> git.sur5r.net Git - cc65/blob - src/cc65/codeinfo.c
Optimization for __bzero.
[cc65] / src / cc65 / codeinfo.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                codeinfo.c                                 */
4 /*                                                                           */
5 /*                  Additional information about 6502 code                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 #include <string.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "coll.h"
42
43 /* cc65 */
44 #include "codeent.h"
45 #include "codeseg.h"
46 #include "datatype.h"
47 #include "error.h"
48 #include "reginfo.h"
49 #include "symtab.h"
50 #include "codeinfo.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* Table with the compare suffixes */
61 static const char CmpSuffixTab [][4] = {
62     "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
63 };
64
65 /* Table listing the function names and code info values for known internally
66  * used functions. This table should get auto-generated in the future.
67  */
68 typedef struct FuncInfo FuncInfo;
69 struct FuncInfo {
70     const char*     Name;       /* Function name */
71     unsigned short  Use;        /* Register usage */
72     unsigned short  Chg;        /* Changed/destroyed registers */
73 };
74
75 static const FuncInfo FuncInfoTable[] = {
76     { "addeq0sp",       REG_AX,               REG_AXY                        },
77     { "addeqysp",       REG_AXY,              REG_AXY                        },
78     { "addysp",         REG_Y,                REG_NONE                       },
79     { "aslax1",         REG_AX,               REG_AX | REG_TMP1              },
80     { "aslax2",         REG_AX,               REG_AX | REG_TMP1              },
81     { "aslax3",         REG_AX,               REG_AX | REG_TMP1              },
82     { "aslax4",         REG_AX,               REG_AX | REG_TMP1              },
83     { "bnega",          REG_A,                REG_AX                         },
84     { "bnegax",         REG_AX,               REG_AX                         },
85     { "bnegeax",        REG_EAX,              REG_EAX                        },
86     { "booleq",         REG_NONE,             REG_AX                         },
87     { "boolge",         REG_NONE,             REG_AX                         },
88     { "boolgt",         REG_NONE,             REG_AX                         },
89     { "boolle",         REG_NONE,             REG_AX                         },
90     { "boollt",         REG_NONE,             REG_AX                         },
91     { "boolne",         REG_NONE,             REG_AX                         },
92     { "booluge",        REG_NONE,             REG_AX                         },
93     { "boolugt",        REG_NONE,             REG_AX                         },
94     { "boolule",        REG_NONE,             REG_AX                         },
95     { "boolult",        REG_NONE,             REG_AX                         },
96     { "complax",        REG_AX,               REG_AX                         },
97     { "decax1",         REG_AX,               REG_AX                         },
98     { "decax2",         REG_AX,               REG_AX                         },
99     { "decax3",         REG_AX,               REG_AX                         },
100     { "decax4",         REG_AX,               REG_AX                         },
101     { "decax5",         REG_AX,               REG_AX                         },
102     { "decax6",         REG_AX,               REG_AX                         },
103     { "decax7",         REG_AX,               REG_AX                         },
104     { "decax8",         REG_AX,               REG_AX                         },
105     { "decaxy",         REG_AXY,              REG_AX | REG_TMP1              },
106     { "deceaxy",        REG_EAXY,             REG_EAX                        },
107     { "decsp1",         REG_NONE,             REG_Y                          },
108     { "decsp2",         REG_NONE,             REG_A                          },
109     { "decsp3",         REG_NONE,             REG_A                          },
110     { "decsp4",         REG_NONE,             REG_A                          },
111     { "decsp5",         REG_NONE,             REG_A                          },
112     { "decsp6",         REG_NONE,             REG_A                          },
113     { "decsp7",         REG_NONE,             REG_A                          },
114     { "decsp8",         REG_NONE,             REG_A                          },
115     { "incax1",         REG_AX,               REG_AX                         },
116     { "incax2",         REG_AX,               REG_AX                         },
117     { "incsp1",         REG_NONE,             REG_NONE                       },
118     { "incsp2",         REG_NONE,             REG_Y                          },
119     { "incsp3",         REG_NONE,             REG_Y                          },
120     { "incsp4",         REG_NONE,             REG_Y                          },
121     { "incsp5",         REG_NONE,             REG_Y                          },
122     { "incsp6",         REG_NONE,             REG_Y                          },
123     { "incsp7",         REG_NONE,             REG_Y                          },
124     { "incsp8",         REG_NONE,             REG_Y                          },
125     { "laddeq",         REG_EAXY|REG_PTR1_LO, REG_EAXY | REG_PTR1_HI         },
126     { "laddeq1",        REG_Y | REG_PTR1_LO,  REG_EAXY | REG_PTR1_HI         },
127     { "laddeqa",        REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI         },
128     { "laddeq0sp",      REG_EAX,              REG_EAXY                       },
129     { "laddeqysp",      REG_EAXY,             REG_EAXY                       },
130     { "ldaidx",         REG_AXY,              REG_AX | REG_PTR1              },
131     { "ldauidx",        REG_AXY,              REG_AX | REG_PTR1              },
132     { "ldax0sp",        REG_NONE,             REG_AXY                        },
133     { "ldaxi",          REG_AX,               REG_AXY | REG_PTR1             },
134     { "ldaxidx",        REG_AXY,              REG_AXY | REG_PTR1             },
135     { "ldaxysp",        REG_Y,                REG_AXY                        },
136     { "ldeax0sp",       REG_NONE,             REG_EAXY                       },
137     { "ldeaxi",         REG_AX,               REG_EAXY | REG_PTR1            },
138     { "ldeaxidx",       REG_AXY,              REG_EAXY | REG_PTR1            },
139     { "ldeaxysp",       REG_Y,                REG_EAXY                       },
140     { "leaasp",         REG_A,                REG_AX                         },
141     { "lsubeq",         REG_EAXY|REG_PTR1_LO, REG_EAXY | REG_PTR1_HI         },
142     { "lsubeq0sp",      REG_EAX,              REG_EAXY                       },
143     { "lsubeq1",        REG_Y | REG_PTR1_LO,  REG_EAXY | REG_PTR1_HI         },
144     { "lsubeqa",        REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI         },
145     { "lsubeqysp",      REG_EAXY,             REG_EAXY                       },
146     { "lsubeq0sp",      REG_EAX,              REG_EAXY                       },
147     { "negax",          REG_AX,               REG_AX                         },
148     { "push0",          REG_NONE,             REG_AXY                        },
149     { "push1",          REG_NONE,             REG_AXY                        },
150     { "push2",          REG_NONE,             REG_AXY                        },
151     { "push3",          REG_NONE,             REG_AXY                        },
152     { "push4",          REG_NONE,             REG_AXY                        },
153     { "push5",          REG_NONE,             REG_AXY                        },
154     { "push6",          REG_NONE,             REG_AXY                        },
155     { "push7",          REG_NONE,             REG_AXY                        },
156     { "pusha",          REG_A,                REG_Y                          },
157     { "pusha0",         REG_A,                REG_XY                         },
158     { "pusha0sp",       REG_NONE,             REG_AY                         },
159     { "pushax",         REG_AX,               REG_Y                          },
160     { "pushaysp",       REG_Y,                REG_AY                         },
161     { "pushc0",         REG_NONE,             REG_A | REG_Y                  },
162     { "pushc1",         REG_NONE,             REG_A | REG_Y                  },
163     { "pushc2",         REG_NONE,             REG_A | REG_Y                  },
164     { "pusheax",        REG_EAX,              REG_Y                          },
165     { "pushw",          REG_AX,               REG_AXY | REG_PTR1             },
166     { "pushw0sp",       REG_NONE,             REG_AXY                        },
167     { "pushwidx",       REG_AXY,              REG_AXY | REG_PTR1             },
168     { "pushwysp",       REG_Y,                REG_AXY                        },
169     { "regswap",        REG_AXY,              REG_AXY | REG_TMP1             },
170     { "regswap1",       REG_XY,               REG_A                          },
171     { "regswap2",       REG_XY,               REG_A | REG_Y                  },
172     { "shlax1",         REG_AX,               REG_AX | REG_TMP1              },
173     { "shlax2",         REG_AX,               REG_AX | REG_TMP1              },
174     { "shlax3",         REG_AX,               REG_AX | REG_TMP1              },
175     { "shlax4",         REG_AX,               REG_AX | REG_TMP1              },
176     { "shrax1",         REG_AX,               REG_AX | REG_TMP1              },
177     { "shrax2",         REG_AX,               REG_AX | REG_TMP1              },
178     { "shrax3",         REG_AX,               REG_AX | REG_TMP1              },
179     { "shrax4",         REG_AX,               REG_AX | REG_TMP1              },
180     { "shreax1",        REG_EAX,              REG_AX | REG_TMP1              },
181     { "shreax2",        REG_EAX,              REG_AX | REG_TMP1              },
182     { "shreax3",        REG_EAX,              REG_AX | REG_TMP1              },
183     { "shreax4",        REG_EAX,              REG_AX | REG_TMP1              },
184     { "staspidx",       REG_A | REG_Y,        REG_Y | REG_TMP1 | REG_PTR1    },
185     { "stax0sp",        REG_AX,               REG_Y                          },
186     { "staxysp",        REG_AXY,              REG_Y                          },
187     { "steax0sp",       REG_EAX,              REG_Y                          },
188     { "steaxysp",       REG_EAXY,             REG_Y                          },
189     { "subeq0sp",       REG_AX,               REG_AXY                        },
190     { "subeqysp",       REG_AXY,              REG_AXY                        },
191     { "tosadda0",       REG_A,                REG_AXY                        },
192     { "tosaddax",       REG_AX,               REG_AXY                        },
193     { "tosanda0",       REG_A,                REG_AXY                        },
194     { "tosandax",       REG_AX,               REG_AXY                        },
195     { "tosdiva0",       REG_AY,               REG_ALL                        },
196     { "tosdivax",       REG_AXY,              REG_ALL                        },
197     { "tosdiveax",      REG_EAXY,             REG_ALL                        },
198     { "toseqeax",       REG_EAX,              REG_AXY | REG_PTR1             },
199     { "tosgeeax",       REG_EAX,              REG_AXY | REG_PTR1             },
200     { "tosgteax",       REG_EAX,              REG_AXY | REG_PTR1             },
201     { "tosicmp",        REG_AX,               REG_AXY | REG_SREG             },
202     { "toslcmp",        REG_EAX,              REG_A | REG_Y | REG_PTR1       },
203     { "tosleeax",       REG_EAX,              REG_AXY | REG_PTR1             },
204     { "toslteax",       REG_EAX,              REG_AXY | REG_PTR1             },
205     { "tosmula0",       REG_AX,               REG_ALL                        },
206     { "tosmulax",       REG_AX,               REG_ALL                        },
207     { "tosmuleax",      REG_EAX,              REG_ALL                        },
208     { "tosneeax",       REG_EAX,              REG_AXY | REG_PTR1             },
209     { "tosshreax",      REG_EAX,              REG_EAXY | REG_PTR1 | REG_PTR2 },
210     { "tossuba0",       REG_A,                REG_AXY                        },
211     { "tossubax",       REG_AX,               REG_AXY                        },
212     { "tossubeax",      REG_EAX,              REG_EAXY                       },
213     { "tosugeeax",      REG_EAX,              REG_AXY | REG_PTR1             },
214     { "tosugteax",      REG_EAX,              REG_AXY | REG_PTR1             },
215     { "tosuleeax",      REG_EAX,              REG_AXY | REG_PTR1             },
216     { "tosulteax",      REG_EAX,              REG_AXY | REG_PTR1             },
217     { "tosumula0",      REG_AX,               REG_ALL                        },
218     { "tosumulax",      REG_AX,               REG_ALL                        },
219     { "tosumuleax",     REG_EAX,              REG_ALL                        },
220     { "tsteax",         REG_EAX,              REG_Y                          },
221     { "utsteax",        REG_EAX,              REG_Y                          },
222 };
223 #define FuncInfoCount   (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
224
225 /* Table with names of zero page locations used by the compiler */
226 static const ZPInfo ZPInfoTable[] = {
227     {   0, "ptr1",      REG_PTR1_LO,    REG_PTR1        },
228     {   0, "ptr1+1",    REG_PTR1_HI,    REG_PTR1        },
229     {   0, "ptr2",      REG_PTR2_LO,    REG_PTR2        },
230     {   0, "ptr2+1",    REG_PTR2_HI,    REG_PTR2        },
231     {   4, "ptr3",      REG_NONE,       REG_NONE        },
232     {   4, "ptr4",      REG_NONE,       REG_NONE        },
233     {   7, "regbank",   REG_NONE,       REG_NONE        },
234     {   0, "regsave",   REG_SAVE_LO,    REG_SAVE        },
235     {   0, "regsave+1", REG_SAVE_HI,    REG_SAVE        },
236     {   0, "sp",        REG_SP_LO,      REG_SP          },
237     {   0, "sp+1",      REG_SP_HI,      REG_SP          },
238     {   0, "sreg",      REG_SREG_LO,    REG_SREG        },
239     {   0, "sreg+1",    REG_SREG_HI,    REG_SREG        },
240     {   0, "tmp1",      REG_TMP1,       REG_TMP1        },
241     {   0, "tmp2",      REG_NONE,       REG_NONE        },
242     {   0, "tmp3",      REG_NONE,       REG_NONE        },
243     {   0, "tmp4",      REG_NONE,       REG_NONE        },
244 };
245 #define ZPInfoCount     (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0]))
246
247
248
249 /*****************************************************************************/
250 /*                                   Code                                    */
251 /*****************************************************************************/
252
253
254
255 static int CompareFuncInfo (const void* Key, const void* Info)
256 /* Compare function for bsearch */
257 {
258     return strcmp (Key, ((const FuncInfo*) Info)->Name);
259 }
260
261
262
263 void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
264 /* For the given function, lookup register information and store it into
265  * the given variables. If the function is unknown, assume it will use and
266  * load all registers.
267  */
268 {
269     /* If the function name starts with an underline, it is an external
270      * function. Search for it in the symbol table. If the function does
271      * not start with an underline, it may be a runtime support function.
272      * Search for it in the list of builtin functions.
273      */
274     if (Name[0] == '_') {
275
276         /* Search in the symbol table, skip the leading underscore */
277         SymEntry* E = FindGlobalSym (Name+1);
278
279         /* Did we find it in the top level table? */
280         if (E && IsTypeFunc (E->Type)) {
281
282             /* A function may use the A or A/X registers if it is a fastcall
283              * function. If it is not a fastcall function but a variadic one,
284              * it will use the Y register (the parameter size is passed here).
285              * In all other cases, no registers are used. However, we assume
286              * that any function will destroy all registers.
287              */
288             FuncDesc* D = E->V.F.Func;
289             if ((D->Flags & FD_FASTCALL) != 0 && D->ParamCount > 0) {
290                 /* Will use registers depending on the last param */
291                 unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type);
292                 if (LastParamSize == 1) {
293                     *Use = REG_A;
294                 } else if (LastParamSize == 2) {
295                     *Use = REG_AX;
296                 } else {
297                     *Use = REG_EAX;
298                 }
299             } else if ((D->Flags & FD_VARIADIC) != 0) {
300                 *Use = REG_Y;
301             } else {
302                 /* Will not use any registers */
303                 *Use = REG_NONE;
304             }
305
306             /* Will destroy all registers */
307             *Chg = REG_ALL;
308
309             /* Done */
310             return;
311         }
312
313     } else if (IsDigit (Name[0]) || Name[0] == '$') {
314
315         /* A call to a numeric address. Assume that anything gets used and
316          * destroyed. This is not a real problem, since numeric addresses
317          * are used mostly in inline assembly anyway.
318          */
319         *Use = REG_ALL;
320         *Chg = REG_ALL;
321         return;
322
323     } else {
324
325         /* Search for the function in the list of builtin functions */
326         const FuncInfo* Info = bsearch (Name, FuncInfoTable, FuncInfoCount,
327                                         sizeof(FuncInfo), CompareFuncInfo);
328
329         /* Do we know the function? */
330         if (Info) {
331             /* Use the information we have */
332             *Use = Info->Use;
333             *Chg = Info->Chg;
334             return;
335         }
336     }
337
338     /* Function not found - assume that the primary register is input, and all
339      * registers are changed
340      */
341     *Use = REG_EAXY;
342     *Chg = REG_ALL;
343 }
344
345
346
347 static int CompareZPInfo (const void* Name, const void* Info)
348 /* Compare function for bsearch */
349 {
350     /* Cast the pointers to the correct data type */
351     const char* N   = (const char*) Name;
352     const ZPInfo* E = (const ZPInfo*) Info;
353
354     /* Do the compare. Be careful because of the length (Info may contain
355      * more than just the zeropage name).
356      */
357     if (E->Len == 0) {
358         /* Do a full compare */
359         return strcmp (N, E->Name);
360     } else {
361         /* Only compare the first part */
362         int Res = strncmp (N, E->Name, E->Len);
363         if (Res == 0 && (N[E->Len] != '\0' && N[E->Len] != '+')) {
364             /* Name is actually longer than Info->Name */
365             Res = -1;
366         }
367         return Res;
368     }
369 }
370
371
372
373 const ZPInfo* GetZPInfo (const char* Name)
374 /* If the given name is a zero page symbol, return a pointer to the info
375  * struct for this symbol, otherwise return NULL.
376  */
377 {
378     /* Search for the zp location in the list */
379     return bsearch (Name, ZPInfoTable, ZPInfoCount,
380                     sizeof(ZPInfo), CompareZPInfo);
381 }
382
383
384
385 static unsigned GetRegInfo2 (CodeSeg* S,
386                              CodeEntry* E,
387                              int Index,
388                              Collection* Visited,
389                              unsigned Used,
390                              unsigned Unused,
391                              unsigned Wanted)
392 /* Recursively called subfunction for GetRegInfo. */
393 {
394     /* Follow the instruction flow recording register usage. */
395     while (1) {
396
397         unsigned R;
398
399         /* Check if we have already visited the current code entry. If so,
400          * bail out.
401          */
402         if (CE_HasMark (E)) {
403             break;
404         }
405
406         /* Mark this entry as already visited */
407         CE_SetMark (E);
408         CollAppend (Visited, E);
409
410         /* Evaluate the used registers */
411         R = E->Use;
412         if (E->OPC == OP65_RTS ||
413             ((E->Info & OF_BRA) != 0 && E->JumpTo == 0)) {
414             /* This instruction will leave the function */
415             R |= S->ExitRegs;
416         }
417         if (R != REG_NONE) {
418             /* We are not interested in the use of any register that has been
419              * used before.
420              */
421             R &= ~Unused;
422             /* Remember the remaining registers */
423             Used |= R;
424         }
425
426         /* Evaluate the changed registers */
427         if ((R = E->Chg) != REG_NONE) {
428             /* We are not interested in the use of any register that has been
429              * used before.
430              */
431             R &= ~Used;
432             /* Remember the remaining registers */
433             Unused |= R;
434         }
435
436         /* If we know about all registers now, bail out */
437         if (((Used | Unused) & Wanted) == Wanted) {
438             break;
439         }
440
441         /* If the instruction is an RTS or RTI, we're done */
442         if ((E->Info & OF_RET) != 0) {
443             break;
444         }
445
446         /* If we have an unconditional branch, follow this branch if possible,
447          * otherwise we're done.
448          */
449         if ((E->Info & OF_UBRA) != 0) {
450
451             /* Does this jump have a valid target? */
452             if (E->JumpTo) {
453
454                 /* Unconditional jump */
455                 E     = E->JumpTo->Owner;
456                 Index = -1;             /* Invalidate */
457
458             } else {
459                 /* Jump outside means we're done */
460                 break;
461             }
462
463         /* In case of conditional branches, follow the branch if possible and
464          * follow the normal flow (branch not taken) afterwards. If we cannot
465          * follow the branch, we're done.
466          */
467         } else if ((E->Info & OF_CBRA) != 0) {
468
469             if (E->JumpTo) {
470
471                 /* Recursively determine register usage at the branch target */
472                 unsigned U1;
473                 unsigned U2;
474
475                 U1 = GetRegInfo2 (S, E->JumpTo->Owner, -1, Visited, Used, Unused, Wanted);
476                 if (U1 == REG_ALL) {
477                     /* All registers used, no need for second call */
478                     return REG_AXY;
479                 }
480                 if (Index < 0) {
481                     Index = CS_GetEntryIndex (S, E);
482                 }
483                 if ((E = CS_GetEntry (S, ++Index)) == 0) {
484                     Internal ("GetRegInfo2: No next entry!");
485                 }
486                 U2 = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted);
487                 return U1 | U2;         /* Used in any of the branches */
488
489             } else {
490                 /* Jump to global symbol */
491                 break;
492             }
493
494         } else {
495
496             /* Just go to the next instruction */
497             if (Index < 0) {
498                 Index = CS_GetEntryIndex (S, E);
499             }
500             E = CS_GetEntry (S, ++Index);
501             if (E == 0) {
502                 /* No next entry */
503                 Internal ("GetRegInfo2: No next entry!");
504             }
505
506         }
507
508     }
509
510     /* Return to the caller the complement of all unused registers */
511     return Used;
512 }
513
514
515
516 static unsigned GetRegInfo1 (CodeSeg* S,
517                              CodeEntry* E,
518                              int Index,
519                              Collection* Visited,
520                              unsigned Used,
521                              unsigned Unused,
522                              unsigned Wanted)
523 /* Recursively called subfunction for GetRegInfo. */
524 {
525     /* Remember the current count of the line collection */
526     unsigned Count = CollCount (Visited);
527
528     /* Call the worker routine */
529     unsigned R = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted);
530
531     /* Restore the old count, unmarking all new entries */
532     unsigned NewCount = CollCount (Visited);
533     while (NewCount-- > Count) {
534         CodeEntry* E = CollAt (Visited, NewCount);
535         CE_ResetMark (E);
536         CollDelete (Visited, NewCount);
537     }
538
539     /* Return the registers used */
540     return R;
541 }
542
543
544
545 unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted)
546 /* Determine register usage information for the instructions starting at the
547  * given index.
548  */
549 {
550     CodeEntry*      E;
551     Collection      Visited;    /* Visited entries */
552     unsigned        R;
553
554     /* Get the code entry for the given index */
555     if (Index >= CS_GetEntryCount (S)) {
556         /* There is no such code entry */
557         return REG_NONE;
558     }
559     E = CS_GetEntry (S, Index);
560
561     /* Initialize the data structure used to collection information */
562     InitCollection (&Visited);
563
564     /* Call the recursive subfunction */
565     R = GetRegInfo1 (S, E, Index, &Visited, REG_NONE, REG_NONE, Wanted);
566
567     /* Delete the line collection */
568     DoneCollection (&Visited);
569
570     /* Return the registers used */
571     return R;
572 }
573
574
575
576 int RegAUsed (struct CodeSeg* S, unsigned Index)
577 /* Check if the value in A is used. */
578 {
579     return (GetRegInfo (S, Index, REG_A) & REG_A) != 0;
580 }
581
582
583
584 int RegXUsed (struct CodeSeg* S, unsigned Index)
585 /* Check if the value in X is used. */
586 {
587     return (GetRegInfo (S, Index, REG_X) & REG_X) != 0;
588 }
589
590
591
592 int RegYUsed (struct CodeSeg* S, unsigned Index)
593 /* Check if the value in Y is used. */
594 {
595     return (GetRegInfo (S, Index, REG_Y) & REG_Y) != 0;
596 }
597
598
599
600 int RegAXUsed (struct CodeSeg* S, unsigned Index)
601 /* Check if the value in A or(!) the value in X are used. */
602 {
603     return (GetRegInfo (S, Index, REG_AX) & REG_AX) != 0;
604 }
605
606
607
608 int RegEAXUsed (struct CodeSeg* S, unsigned Index)
609 /* Check if any of the four bytes in EAX are used. */
610 {
611     return (GetRegInfo (S, Index, REG_EAX) & REG_EAX) != 0;
612 }
613
614
615
616 unsigned GetKnownReg (unsigned Use, const RegContents* RC)
617 /* Return the register or zero page location from the set in Use, thats
618  * contents are known. If Use does not contain any register, or if the
619  * register in question does not have a known value, return REG_NONE.
620  */
621 {
622     if ((Use & REG_A) != 0) {
623         return (RC == 0 || RC->RegA >= 0)? REG_A : REG_NONE;
624     } else if ((Use & REG_X) != 0) {
625         return (RC == 0 || RC->RegX >= 0)? REG_X : REG_NONE;
626     } else if ((Use & REG_Y) != 0) {
627         return (RC == 0 || RC->RegY >= 0)? REG_Y : REG_NONE;
628     } else if ((Use & REG_TMP1) != 0) {
629         return (RC == 0 || RC->Tmp1 >= 0)? REG_TMP1 : REG_NONE;
630     } else if ((Use & REG_PTR1_LO) != 0) {
631         return (RC == 0 || RC->Ptr1Lo >= 0)? REG_PTR1_LO : REG_NONE;
632     } else if ((Use & REG_PTR1_HI) != 0) {
633         return (RC == 0 || RC->Ptr1Hi >= 0)? REG_PTR1_HI : REG_NONE;
634     } else if ((Use & REG_SREG_LO) != 0) {
635         return (RC == 0 || RC->SRegLo >= 0)? REG_SREG_LO : REG_NONE;
636     } else if ((Use & REG_SREG_HI) != 0) {
637         return (RC == 0 || RC->SRegHi >= 0)? REG_SREG_HI : REG_NONE;
638     } else {
639         return REG_NONE;
640     }
641 }
642
643
644
645 static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
646 /* Search for a compare condition by the given code using the given length */
647 {
648     unsigned I;
649
650     /* Linear search */
651     for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
652         if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
653             /* Found */
654             return I;
655         }
656     }
657
658     /* Not found */
659     return CMP_INV;
660 }
661
662
663
664 cmp_t FindBoolCmpCond (const char* Name)
665 /* Check if the given string is the name of one of the boolean transformer
666  * subroutine, and if so, return the condition that is evaluated by this
667  * routine. Return CMP_INV if the condition is not recognised.
668  */
669 {
670     /* Check for the correct subroutine name */
671     if (strncmp (Name, "bool", 4) == 0) {
672         /* Name is ok, search for the code in the table */
673         return FindCmpCond (Name+4, strlen(Name)-4);
674     } else {
675         /* Not found */
676         return CMP_INV;
677     }
678 }
679
680
681
682 cmp_t FindTosCmpCond (const char* Name)
683 /* Check if this is a call to one of the TOS compare functions (tosgtax).
684  * Return the condition code or CMP_INV on failure.
685  */
686 {
687     unsigned Len = strlen (Name);
688
689     /* Check for the correct subroutine name */
690     if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
691         /* Name is ok, search for the code in the table */
692         return FindCmpCond (Name+3, Len-3-2);
693     } else {
694         /* Not found */
695         return CMP_INV;
696     }
697 }
698
699
700