1 /*****************************************************************************/
9 /* (C) 2002-2005, 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, provided that the next insn doesn't use flags
71 /* Walk over the entries */
73 while (I < CS_GetEntryCount (S)) {
78 L[0] = CS_GetEntry (S, I);
80 /* Check for the sequence */
81 if (L[0]->OPC == OP65_LDY &&
82 CE_IsConstImm (L[0]) &&
84 !CS_RangeHasLabel (S, I+1, 3) &&
85 CS_GetEntries (S, L+1, I+1, 4) &&
86 CE_IsCallTo (L[1], "staxysp") &&
87 L[2]->OPC == OP65_LDY &&
88 CE_IsKnownImm (L[2], L[0]->Num + 1) &&
89 CE_IsCallTo (L[3], "ldaxysp") &&
90 !CE_UseLoadFlags (L[4])) {
92 /* Register has already the correct value, remove the loads */
93 CS_DelEntries (S, I+2, 2);
95 /* Remember, we had changes */
105 /* Return the number of changes made */
111 unsigned OptStore2 (CodeSeg* S)
112 /* Search for a call to staxysp. If the ax register is not used later, and
113 * the value is constant, just use the A register and store directly into the
118 unsigned Changes = 0;
120 /* Generate register info */
123 /* Walk over the entries */
125 while (I < CS_GetEntryCount (S)) {
128 CodeEntry* E = CS_GetEntry (S, I);
130 /* Get the input registers */
131 const RegInfo* RI = E->RI;
133 /* Check for the call */
134 if (CE_IsCallTo (E, "staxysp") &&
135 RegValIsKnown (RI->In.RegA) &&
136 RegValIsKnown (RI->In.RegX) &&
137 RegValIsKnown (RI->In.RegY) &&
138 !RegAXUsed (S, I+1)) {
140 /* Get the register values */
141 unsigned char A = RI->In.RegA;
142 unsigned char X = RI->In.RegX;
143 unsigned char Y = RI->In.RegY;
145 /* Setup other variables */
147 unsigned IP = I + 1; /* Insertion point */
149 /* Replace the store. We will not remove the loads, since this is
150 * too complex and will be done by other optimizer steps.
152 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
153 CS_InsertEntry (S, N, IP++);
154 InsertStore (S, &IP, E->LI);
156 /* Check if we can store one of the other bytes */
158 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
159 CS_InsertEntry (S, N, IP++);
161 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
162 CS_InsertEntry (S, N, IP++);
163 InsertStore (S, &IP, E->LI);
165 /* Remove the call */
168 /* Remember, we had changes */
178 /* Free the register info */
181 /* Return the number of changes made */
187 unsigned OptStore3 (CodeSeg* S)
188 /* Search for a call to steaxysp. If the eax register is not used later, and
189 * the value is constant, just use the A register and store directly into the
194 unsigned Changes = 0;
196 /* Generate register info */
199 /* Walk over the entries */
201 while (I < CS_GetEntryCount (S)) {
204 CodeEntry* E = CS_GetEntry (S, I);
206 /* Get the input registers */
207 const RegInfo* RI = E->RI;
209 /* Check for the call */
210 if (CE_IsCallTo (E, "steaxysp") &&
211 RegValIsKnown (RI->In.RegA) &&
212 RegValIsKnown (RI->In.RegX) &&
213 RegValIsKnown (RI->In.RegY) &&
214 RegValIsKnown (RI->In.SRegLo) &&
215 RegValIsKnown (RI->In.SRegHi) &&
216 !RegEAXUsed (S, I+1)) {
218 /* Get the register values */
219 unsigned char A = RI->In.RegA;
220 unsigned char X = RI->In.RegX;
221 unsigned char Y = RI->In.RegY;
222 unsigned char L = RI->In.SRegLo;
223 unsigned char H = RI->In.SRegHi;
225 /* Setup other variables */
228 unsigned IP = I + 1; /* Insertion point */
230 /* Replace the store. We will not remove the loads, since this is
231 * too complex and will be done by other optimizer steps.
233 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
234 CS_InsertEntry (S, N, IP++);
235 InsertStore (S, &IP, E->LI);
238 /* Check if we can store one of the other bytes */
239 if (A == X && (Done & 0x02) == 0) {
240 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
241 CS_InsertEntry (S, N, IP++);
242 InsertStore (S, &IP, E->LI);
245 if (A == L && (Done & 0x04) == 0) {
246 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
247 CS_InsertEntry (S, N, IP++);
248 InsertStore (S, &IP, E->LI);
251 if (A == H && (Done & 0x08) == 0) {
252 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
253 CS_InsertEntry (S, N, IP++);
254 InsertStore (S, &IP, E->LI);
258 /* Store the second byte */
259 if ((Done & 0x02) == 0) {
260 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
261 CS_InsertEntry (S, N, IP++);
262 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
263 CS_InsertEntry (S, N, IP++);
264 InsertStore (S, &IP, E->LI);
268 /* Check if we can store one of the other bytes */
269 if (X == L && (Done & 0x04) == 0) {
270 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
271 CS_InsertEntry (S, N, IP++);
272 InsertStore (S, &IP, E->LI);
275 if (X == H && (Done & 0x08) == 0) {
276 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
277 CS_InsertEntry (S, N, IP++);
278 InsertStore (S, &IP, E->LI);
282 /* Store the third byte */
283 if ((Done & 0x04) == 0) {
284 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI);
285 CS_InsertEntry (S, N, IP++);
286 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
287 CS_InsertEntry (S, N, IP++);
288 InsertStore (S, &IP, E->LI);
292 /* Check if we can store one of the other bytes */
293 if (L == H && (Done & 0x08) == 0) {
294 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
295 CS_InsertEntry (S, N, IP++);
296 InsertStore (S, &IP, E->LI);
300 /* Store the fourth byte */
301 if ((Done & 0x08) == 0) {
302 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI);
303 CS_InsertEntry (S, N, IP++);
304 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
305 CS_InsertEntry (S, N, IP++);
306 InsertStore (S, &IP, E->LI);
310 /* Remove the call */
313 /* Remember, we had changes */
323 /* Free the register info */
326 /* Return the number of changes made */
332 unsigned OptStore4 (CodeSeg* S)
333 /* Search for the sequence
340 * and remove the useless load, provided that the next insn doesn't use flags
344 unsigned Changes = 0;
346 /* Walk over the entries */
348 while (I < CS_GetEntryCount (S)) {
353 L[0] = CS_GetEntry (S, I);
355 /* Check for the sequence */
356 if (L[0]->OPC == OP65_STA &&
357 (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) &&
358 !CS_RangeHasLabel (S, I+1, 3) &&
359 CS_GetEntries (S, L+1, I+1, 4) &&
360 L[1]->OPC == OP65_STX &&
361 L[1]->AM == L[0]->AM &&
362 L[2]->OPC == OP65_LDA &&
363 L[2]->AM == L[0]->AM &&
364 L[3]->OPC == OP65_LDX &&
365 L[3]->AM == L[1]->AM &&
366 strcmp (L[0]->Arg, L[2]->Arg) == 0 &&
367 strcmp (L[1]->Arg, L[3]->Arg) == 0 &&
368 !CE_UseLoadFlags (L[4])) {
370 /* Register has already the correct value, remove the loads */
371 CS_DelEntries (S, I+2, 2);
373 /* Remember, we had changes */
383 /* Return the number of changes made */