1 /*****************************************************************************/
9 /* (C) 2002-2006, Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
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 /*****************************************************************************/
39 #include "coptstore.h"
43 /*****************************************************************************/
45 /*****************************************************************************/
49 static void InsertStore (CodeSeg* S, unsigned* IP, LineInfo* LI)
51 CodeEntry* X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, LI);
52 CS_InsertEntry (S, X, (*IP)++);
57 unsigned OptStore1 (CodeSeg* S)
58 /* Search for the sequence
65 * and remove the useless load.
70 /* Walk over the entries */
72 while (I < CS_GetEntryCount (S)) {
77 L[0] = CS_GetEntry (S, I);
79 /* Check for the sequence */
80 if (L[0]->OPC == OP65_LDY &&
81 CE_IsConstImm (L[0]) &&
83 !CS_RangeHasLabel (S, I+1, 3) &&
84 CS_GetEntries (S, L+1, I+1, 3) &&
85 CE_IsCallTo (L[1], "staxysp") &&
86 L[2]->OPC == OP65_LDY &&
87 CE_IsKnownImm (L[2], L[0]->Num + 1) &&
88 CE_IsCallTo (L[3], "ldaxysp")) {
90 /* Register has already the correct value, remove the loads */
91 CS_DelEntries (S, I+2, 2);
93 /* Remember, we had changes */
103 /* Return the number of changes made */
109 unsigned OptStore2 (CodeSeg* S)
110 /* Search for a call to staxysp. If the ax register is not used later, and
111 * the value is constant, just use the A register and store directly into the
116 unsigned Changes = 0;
118 /* Generate register info */
121 /* Walk over the entries */
123 while (I < CS_GetEntryCount (S)) {
126 CodeEntry* E = CS_GetEntry (S, I);
128 /* Get the input registers */
129 const RegInfo* RI = E->RI;
131 /* Check for the call */
132 if (CE_IsCallTo (E, "staxysp") &&
133 RegValIsKnown (RI->In.RegA) &&
134 RegValIsKnown (RI->In.RegX) &&
135 RegValIsKnown (RI->In.RegY) &&
136 !RegAXUsed (S, I+1)) {
138 /* Get the register values */
139 unsigned char A = RI->In.RegA;
140 unsigned char X = RI->In.RegX;
141 unsigned char Y = RI->In.RegY;
143 /* Setup other variables */
145 unsigned IP = I + 1; /* Insertion point */
147 /* Replace the store. We will not remove the loads, since this is
148 * too complex and will be done by other optimizer steps.
150 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
151 CS_InsertEntry (S, N, IP++);
152 InsertStore (S, &IP, E->LI);
154 /* Check if we can store one of the other bytes */
156 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
157 CS_InsertEntry (S, N, IP++);
159 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
160 CS_InsertEntry (S, N, IP++);
161 InsertStore (S, &IP, E->LI);
163 /* Remove the call */
166 /* Remember, we had changes */
176 /* Free the register info */
179 /* Return the number of changes made */
185 unsigned OptStore3 (CodeSeg* S)
186 /* Search for a call to steaxysp. If the eax register is not used later, and
187 * the value is constant, just use the A register and store directly into the
192 unsigned Changes = 0;
194 /* Generate register info */
197 /* Walk over the entries */
199 while (I < CS_GetEntryCount (S)) {
202 CodeEntry* E = CS_GetEntry (S, I);
204 /* Get the input registers */
205 const RegInfo* RI = E->RI;
207 /* Check for the call */
208 if (CE_IsCallTo (E, "steaxysp") &&
209 RegValIsKnown (RI->In.RegA) &&
210 RegValIsKnown (RI->In.RegX) &&
211 RegValIsKnown (RI->In.RegY) &&
212 RegValIsKnown (RI->In.SRegLo) &&
213 RegValIsKnown (RI->In.SRegHi) &&
214 !RegEAXUsed (S, I+1)) {
216 /* Get the register values */
217 unsigned char A = RI->In.RegA;
218 unsigned char X = RI->In.RegX;
219 unsigned char Y = RI->In.RegY;
220 unsigned char L = RI->In.SRegLo;
221 unsigned char H = RI->In.SRegHi;
223 /* Setup other variables */
226 unsigned IP = I + 1; /* Insertion point */
228 /* Replace the store. We will not remove the loads, since this is
229 * too complex and will be done by other optimizer steps.
231 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
232 CS_InsertEntry (S, N, IP++);
233 InsertStore (S, &IP, E->LI);
236 /* Check if we can store one of the other bytes */
237 if (A == X && (Done & 0x02) == 0) {
238 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
239 CS_InsertEntry (S, N, IP++);
240 InsertStore (S, &IP, E->LI);
243 if (A == L && (Done & 0x04) == 0) {
244 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
245 CS_InsertEntry (S, N, IP++);
246 InsertStore (S, &IP, E->LI);
249 if (A == H && (Done & 0x08) == 0) {
250 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
251 CS_InsertEntry (S, N, IP++);
252 InsertStore (S, &IP, E->LI);
256 /* Store the second byte */
257 if ((Done & 0x02) == 0) {
258 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
259 CS_InsertEntry (S, N, IP++);
260 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
261 CS_InsertEntry (S, N, IP++);
262 InsertStore (S, &IP, E->LI);
266 /* Check if we can store one of the other bytes */
267 if (X == L && (Done & 0x04) == 0) {
268 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
269 CS_InsertEntry (S, N, IP++);
270 InsertStore (S, &IP, E->LI);
273 if (X == H && (Done & 0x08) == 0) {
274 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
275 CS_InsertEntry (S, N, IP++);
276 InsertStore (S, &IP, E->LI);
280 /* Store the third byte */
281 if ((Done & 0x04) == 0) {
282 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI);
283 CS_InsertEntry (S, N, IP++);
284 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
285 CS_InsertEntry (S, N, IP++);
286 InsertStore (S, &IP, E->LI);
290 /* Check if we can store one of the other bytes */
291 if (L == H && (Done & 0x08) == 0) {
292 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
293 CS_InsertEntry (S, N, IP++);
294 InsertStore (S, &IP, E->LI);
298 /* Store the fourth byte */
299 if ((Done & 0x08) == 0) {
300 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI);
301 CS_InsertEntry (S, N, IP++);
302 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
303 CS_InsertEntry (S, N, IP++);
304 InsertStore (S, &IP, E->LI);
308 /* Remove the call */
311 /* Remember, we had changes */
321 /* Free the register info */
324 /* Return the number of changes made */
330 unsigned OptStore4 (CodeSeg* S)
331 /* Search for the sequence
338 * and remove the useless load, provided that the next insn doesn't use flags
342 unsigned Changes = 0;
344 /* Walk over the entries */
346 while (I < CS_GetEntryCount (S)) {
351 L[0] = CS_GetEntry (S, I);
353 /* Check for the sequence */
354 if (L[0]->OPC == OP65_STA &&
355 (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) &&
356 !CS_RangeHasLabel (S, I+1, 3) &&
357 CS_GetEntries (S, L+1, I+1, 4) &&
358 L[1]->OPC == OP65_STX &&
359 L[1]->AM == L[0]->AM &&
360 L[2]->OPC == OP65_LDA &&
361 L[2]->AM == L[0]->AM &&
362 L[3]->OPC == OP65_LDX &&
363 L[3]->AM == L[1]->AM &&
364 strcmp (L[0]->Arg, L[2]->Arg) == 0 &&
365 strcmp (L[1]->Arg, L[3]->Arg) == 0 &&
366 !CE_UseLoadFlags (L[4])) {
368 /* Register has already the correct value, remove the loads */
369 CS_DelEntries (S, I+2, 2);
371 /* Remember, we had changes */
381 /* Return the number of changes made */
387 unsigned OptStore5 (CodeSeg* S)
388 /* Search for the sequence
402 * if X is not used later. This replacement doesn't save any cycles or bytes,
403 * but it keeps the value of X, which may be reused later.
406 unsigned Changes = 0;
408 /* Walk over the entries */
410 while (I < CS_GetEntryCount (S)) {
415 L[0] = CS_GetEntry (S, I);
417 /* Check for the sequence */
418 if (L[0]->OPC == OP65_LDA &&
419 !CS_RangeHasLabel (S, I+1, 3) &&
420 CS_GetEntries (S, L+1, I+1, 3) &&
421 L[1]->OPC == OP65_LDX &&
422 L[2]->OPC == OP65_STA &&
423 L[3]->OPC == OP65_STX &&
424 !RegXUsed (S, I+4)) {
428 /* Insert the code after the sequence */
429 X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
430 CS_InsertEntry (S, X, I+4);
431 X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
432 CS_InsertEntry (S, X, I+5);
434 /* Delete the old code */
435 CS_DelEntry (S, I+3);
436 CS_DelEntry (S, I+1);
438 /* Remember, we had changes */
447 /* Return the number of changes made */