1 /*****************************************************************************/
5 /* Additional information about 6502 code */
9 /* (C) 2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
47 /*****************************************************************************/
49 /*****************************************************************************/
53 /* Table listing the function names and code info values for known internally
54 * used functions. This table should get auto-generated in the future.
56 typedef struct FuncInfo FuncInfo;
58 const char* Name; /* Function name */
59 unsigned char Use; /* Register usage */
60 unsigned char Chg; /* Changed/destroyed registers */
63 static const FuncInfo FuncInfoTable[] = {
64 { "booleq", REG_NONE, REG_AX },
65 { "boolge", REG_NONE, REG_AX },
66 { "boolgt", REG_NONE, REG_AX },
67 { "boolle", REG_NONE, REG_AX },
68 { "boollt", REG_NONE, REG_AX },
69 { "boolne", REG_NONE, REG_AX },
70 { "booluge", REG_NONE, REG_AX },
71 { "boolugt", REG_NONE, REG_AX },
72 { "boolule", REG_NONE, REG_AX },
73 { "boolult", REG_NONE, REG_AX },
74 { "decax1", REG_AX, REG_AX },
75 { "decax2", REG_AX, REG_AX },
76 { "decax3", REG_AX, REG_AX },
77 { "decax4", REG_AX, REG_AX },
78 { "decax5", REG_AX, REG_AX },
79 { "decax6", REG_AX, REG_AX },
80 { "decax7", REG_AX, REG_AX },
81 { "decax8", REG_AX, REG_AX },
82 { "decaxy", REG_AXY, REG_AX },
83 { "decsp2", REG_NONE, REG_A },
84 { "decsp3", REG_NONE, REG_A },
85 { "decsp4", REG_NONE, REG_A },
86 { "decsp5", REG_NONE, REG_A },
87 { "decsp6", REG_NONE, REG_A },
88 { "decsp7", REG_NONE, REG_A },
89 { "decsp8", REG_NONE, REG_A },
90 { "ldax0sp", REG_Y, REG_AX },
91 { "ldaxysp", REG_Y, REG_AX },
92 { "pusha", REG_A, REG_Y },
93 { "pusha0", REG_A, REG_XY },
94 { "pushax", REG_AX, REG_Y },
95 { "pushw0sp", REG_NONE, REG_AXY },
96 { "pushwysp", REG_Y, REG_AXY },
97 { "tosicmp", REG_AX, REG_AXY },
99 #define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
101 /* Structure used to pass information to the RegValUsedInt1 and 2 functions */
102 typedef struct RVUInfo RVUInfo;
104 Collection VisitedLines; /* Lines already visited */
109 /*****************************************************************************/
111 /*****************************************************************************/
115 static int CompareFuncInfo (const void* Key, const void* Info)
116 /* Compare function for bsearch */
118 return strcmp (Key, ((const FuncInfo*) Info)->Name);
123 void GetFuncInfo (const char* Name, unsigned char* Use, unsigned char* Chg)
124 /* For the given function, lookup register information and combine it with
125 * the information already in place. If the function is unknown, assume it
126 * will use all registers and load all registers.
127 * See codeinfo.h for possible flags.
130 /* Search for the function */
131 const FuncInfo* Info = bsearch (Name, FuncInfoTable, FuncInfoCount,
132 sizeof(FuncInfo), CompareFuncInfo);
134 /* Do we know the function? */
136 /* Use the information we have */
148 static unsigned RVUInt2 (Line* L,
149 LineColl* LC, /* To remember visited lines */
150 unsigned Used, /* Definitely used registers */
151 unsigned Unused) /* Definitely unused registers */
152 /* Subfunction for RegValUsed. Will be called recursively in case of branches. */
156 /* Check the following instructions. We classifiy them into primary
157 * loads (register value not used), neutral (check next instruction),
158 * and unknown (assume register was used).
164 /* Get the next line and follow jumps */
167 /* Handle jumps to local labels (continue there) */
168 if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) {
169 /* Get the target of the jump */
170 L = GetTargetLine (L->Line+5);
173 /* Get the next line, skip local labels */
175 L = NextCodeSegLine (L);
176 } while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
178 /* Bail out if we're done */
179 if (L == 0 || IsExtLabel (L)) {
180 /* End of function reached */
184 /* Check if we had this line already. If so, bail out, if not,
185 * add it to the list of known lines.
187 if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
191 } while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
193 /* Special handling of code hints */
194 if (IsHintLine (L)) {
196 if (IsHint (L, "a:-") && (Used & REG_A) == 0) {
198 } else if (IsHint (L, "x:-") && (Used & REG_X) == 0) {
200 } else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) {
204 /* Special handling for branches */
205 } else if (LineMatchX (L, ShortBranches) >= 0 ||
206 LineMatchX (L, LongBranches) >= 0) {
207 const char* Target = L->Line+5;
208 if (Target[0] == 'L') {
209 /* Jump to local label. Check the register usage starting at
210 * the branch target and at the code following the branch.
211 * All registers that are unused in both execution flows are
212 * returned as unused.
215 U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
216 U1 = RVUInt1 (L, LC, Used, Unused);
217 return U1 | U2; /* Used in any of the branches */
221 /* Search for the instruction in this line */
224 /* If we don't find it, assume all other registers are used */
229 /* Evaluate the use flags, check for addressing modes */
231 if (IsXAddrMode (L)) {
233 } else if (IsYAddrMode (L)) {
237 /* Remove registers that were already new loaded */
240 /* Remember the remaining registers */
244 /* Evaluate the load flags */
247 /* Remove registers that were already used */
250 /* Remember the remaining registers */
256 /* If we know about all registers, bail out */
257 if ((Used | Unused) == REG_ALL) {
263 /* Return to the caller the complement of all unused registers */
264 return ~Unused & REG_ALL;
269 static unsigned RVUInt1 (Line* L,
270 LineColl* LC, /* To remember visited lines */
271 unsigned Used, /* Definitely used registers */
272 unsigned Unused) /* Definitely unused registers */
273 /* Subfunction for RegValUsed. Will be called recursively in case of branches. */
275 /* Remember the current count of the line collection */
276 unsigned Count = LC->Count;
278 /* Call the worker routine */
279 unsigned R = RVUInt2 (L, LC, Used, Unused);
281 /* Restore the old count */
284 /* Return the result */
290 static unsigned RegValUsed (Line* Start)
291 /* Check the next instructions after the one in L for register usage. If
292 * a register is used as an index, or in a store or other instruction, it
293 * is assumed to be used. If a register is loaded with a value, before it
294 * was used by one of the actions described above, it is assumed unused.
295 * If the end of the lookahead is reached, all registers that are uncertain
296 * are marked as used.
297 * The result of the search is returned.
302 /* Create a new line collection and enter the start line */
303 LineColl* LC = NewLineColl (256);
304 LCAddLine (LC, Start);
306 /* Call the recursive subfunction */
307 R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
309 /* Delete the line collection */
312 /* Return the registers used */
318 static int RegAUsed (Line* Start)
319 /* Check if the value in A is used. */
321 return (RegValUsed (Start) & REG_A) != 0;
326 static int RegXUsed (Line* Start)
327 /* Check if the value in X is used. */
329 return (RegValUsed (Start) & REG_X) != 0;
334 static int RegYUsed (Line* Start)
335 /* Check if the value in Y is used. */
337 return (RegValUsed (Start) & REG_Y) != 0;