1 /*****************************************************************************/
9 /* (C) 2002-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 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 /* Walk over the entries */
120 while (I < CS_GetEntryCount (S)) {
123 CodeEntry* E = CS_GetEntry (S, I);
125 /* Get the input registers */
126 const RegInfo* RI = E->RI;
128 /* Check for the call */
129 if (CE_IsCallTo (E, "staxysp") &&
130 RegValIsKnown (RI->In.RegA) &&
131 RegValIsKnown (RI->In.RegX) &&
132 RegValIsKnown (RI->In.RegY) &&
133 !RegAXUsed (S, I+1)) {
135 /* Get the register values */
136 unsigned char A = RI->In.RegA;
137 unsigned char X = RI->In.RegX;
138 unsigned char Y = RI->In.RegY;
140 /* Setup other variables */
142 unsigned IP = I + 1; /* Insertion point */
144 /* Replace the store. We will not remove the loads, since this is
145 * too complex and will be done by other optimizer steps.
147 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
148 CS_InsertEntry (S, N, IP++);
149 InsertStore (S, &IP, E->LI);
151 /* Check if we can store one of the other bytes */
153 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
154 CS_InsertEntry (S, N, IP++);
156 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
157 CS_InsertEntry (S, N, IP++);
158 InsertStore (S, &IP, E->LI);
160 /* Remove the call */
163 /* Remember, we had changes */
173 /* Return the number of changes made */
179 unsigned OptStore3 (CodeSeg* S)
180 /* Search for a call to steaxysp. If the eax register is not used later, and
181 * the value is constant, just use the A register and store directly into the
186 unsigned Changes = 0;
188 /* Walk over the entries */
190 while (I < CS_GetEntryCount (S)) {
193 CodeEntry* E = CS_GetEntry (S, I);
195 /* Get the input registers */
196 const RegInfo* RI = E->RI;
198 /* Check for the call */
199 if (CE_IsCallTo (E, "steaxysp") &&
200 RegValIsKnown (RI->In.RegA) &&
201 RegValIsKnown (RI->In.RegX) &&
202 RegValIsKnown (RI->In.RegY) &&
203 RegValIsKnown (RI->In.SRegLo) &&
204 RegValIsKnown (RI->In.SRegHi) &&
205 !RegEAXUsed (S, I+1)) {
207 /* Get the register values */
208 unsigned char A = RI->In.RegA;
209 unsigned char X = RI->In.RegX;
210 unsigned char Y = RI->In.RegY;
211 unsigned char L = RI->In.SRegLo;
212 unsigned char H = RI->In.SRegHi;
214 /* Setup other variables */
217 unsigned IP = I + 1; /* Insertion point */
219 /* Replace the store. We will not remove the loads, since this is
220 * too complex and will be done by other optimizer steps.
222 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
223 CS_InsertEntry (S, N, IP++);
224 InsertStore (S, &IP, E->LI);
227 /* Check if we can store one of the other bytes */
228 if (A == X && (Done & 0x02) == 0) {
229 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
230 CS_InsertEntry (S, N, IP++);
231 InsertStore (S, &IP, E->LI);
234 if (A == L && (Done & 0x04) == 0) {
235 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
236 CS_InsertEntry (S, N, IP++);
237 InsertStore (S, &IP, E->LI);
240 if (A == H && (Done & 0x08) == 0) {
241 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
242 CS_InsertEntry (S, N, IP++);
243 InsertStore (S, &IP, E->LI);
247 /* Store the second byte */
248 if ((Done & 0x02) == 0) {
249 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
250 CS_InsertEntry (S, N, IP++);
251 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
252 CS_InsertEntry (S, N, IP++);
253 InsertStore (S, &IP, E->LI);
257 /* Check if we can store one of the other bytes */
258 if (X == L && (Done & 0x04) == 0) {
259 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
260 CS_InsertEntry (S, N, IP++);
261 InsertStore (S, &IP, E->LI);
264 if (X == H && (Done & 0x08) == 0) {
265 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
266 CS_InsertEntry (S, N, IP++);
267 InsertStore (S, &IP, E->LI);
271 /* Store the third byte */
272 if ((Done & 0x04) == 0) {
273 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI);
274 CS_InsertEntry (S, N, IP++);
275 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
276 CS_InsertEntry (S, N, IP++);
277 InsertStore (S, &IP, E->LI);
281 /* Check if we can store one of the other bytes */
282 if (L == H && (Done & 0x08) == 0) {
283 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
284 CS_InsertEntry (S, N, IP++);
285 InsertStore (S, &IP, E->LI);
289 /* Store the fourth byte */
290 if ((Done & 0x08) == 0) {
291 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI);
292 CS_InsertEntry (S, N, IP++);
293 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
294 CS_InsertEntry (S, N, IP++);
295 InsertStore (S, &IP, E->LI);
299 /* Remove the call */
302 /* Remember, we had changes */
312 /* Return the number of changes made */
318 unsigned OptStore4 (CodeSeg* S)
319 /* Search for the sequence
326 * and remove the useless load, provided that the next insn doesn't use flags
330 unsigned Changes = 0;
332 /* Walk over the entries */
334 while (I < CS_GetEntryCount (S)) {
339 L[0] = CS_GetEntry (S, I);
341 /* Check for the sequence */
342 if (L[0]->OPC == OP65_STA &&
343 (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) &&
344 !CS_RangeHasLabel (S, I+1, 3) &&
345 CS_GetEntries (S, L+1, I+1, 4) &&
346 L[1]->OPC == OP65_STX &&
347 L[1]->AM == L[0]->AM &&
348 L[2]->OPC == OP65_LDA &&
349 L[2]->AM == L[0]->AM &&
350 L[3]->OPC == OP65_LDX &&
351 L[3]->AM == L[1]->AM &&
352 strcmp (L[0]->Arg, L[2]->Arg) == 0 &&
353 strcmp (L[1]->Arg, L[3]->Arg) == 0 &&
354 !CE_UseLoadFlags (L[4])) {
356 /* Register has already the correct value, remove the loads */
357 CS_DelEntries (S, I+2, 2);
359 /* Remember, we had changes */
369 /* Return the number of changes made */
375 unsigned OptStore5 (CodeSeg* S)
376 /* Search for the sequence
390 * if X is not used later. This replacement doesn't save any cycles or bytes,
391 * but it keeps the value of X, which may be reused later.
394 unsigned Changes = 0;
396 /* Walk over the entries */
398 while (I < CS_GetEntryCount (S)) {
403 L[0] = CS_GetEntry (S, I);
405 /* Check for the sequence */
406 if (L[0]->OPC == OP65_LDA &&
407 !CS_RangeHasLabel (S, I+1, 3) &&
408 CS_GetEntries (S, L+1, I+1, 3) &&
409 L[1]->OPC == OP65_LDX &&
410 L[2]->OPC == OP65_STA &&
411 L[3]->OPC == OP65_STX &&
412 !RegXUsed (S, I+4)) {
416 /* Insert the code after the sequence */
417 X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
418 CS_InsertEntry (S, X, I+4);
419 X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
420 CS_InsertEntry (S, X, I+5);
422 /* Delete the old code */
423 CS_DelEntry (S, I+3);
424 CS_DelEntry (S, I+1);
426 /* Remember, we had changes */
435 /* Return the number of changes made */