1 /*****************************************************************************/
9 /* (C) 2002-2003 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 &&
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 &&
89 L[2]->Num == L[0]->Num + 1 &&
90 CE_IsCallTo (L[3], "ldaxysp") &&
91 !CE_UseLoadFlags (L[4])) {
93 /* Register has already the correct value, remove the loads */
94 CS_DelEntries (S, I+2, 2);
96 /* Remember, we had changes */
106 /* Return the number of changes made */
112 unsigned OptStore2 (CodeSeg* S)
113 /* Search for a call to staxysp. If the ax register is not used later, and
114 * the value is constant, just use the A register and store directly into the
119 unsigned Changes = 0;
121 /* Generate register info */
124 /* Walk over the entries */
126 while (I < CS_GetEntryCount (S)) {
129 CodeEntry* E = CS_GetEntry (S, I);
131 /* Get the input registers */
132 const RegInfo* RI = E->RI;
134 /* Check for the call */
135 if (CE_IsCallTo (E, "staxysp") &&
136 RegValIsKnown (RI->In.RegA) &&
137 RegValIsKnown (RI->In.RegX) &&
138 RegValIsKnown (RI->In.RegY) &&
139 !RegAXUsed (S, I+1)) {
141 /* Get the register values */
142 unsigned char A = RI->In.RegA;
143 unsigned char X = RI->In.RegX;
144 unsigned char Y = RI->In.RegY;
146 /* Setup other variables */
148 unsigned IP = I + 1; /* Insertion point */
150 /* Replace the store. We will not remove the loads, since this is
151 * too complex and will be done by other optimizer steps.
153 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
154 CS_InsertEntry (S, N, IP++);
155 InsertStore (S, &IP, E->LI);
157 /* Check if we can store one of the other bytes */
159 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
160 CS_InsertEntry (S, N, IP++);
162 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
163 CS_InsertEntry (S, N, IP++);
164 InsertStore (S, &IP, E->LI);
166 /* Remove the call */
169 /* Remember, we had changes */
179 /* Free the register info */
182 /* Return the number of changes made */
188 unsigned OptStore3 (CodeSeg* S)
189 /* Search for a call to steaxysp. If the eax register is not used later, and
190 * the value is constant, just use the A register and store directly into the
195 unsigned Changes = 0;
197 /* Generate register info */
200 /* Walk over the entries */
202 while (I < CS_GetEntryCount (S)) {
205 CodeEntry* E = CS_GetEntry (S, I);
207 /* Get the input registers */
208 const RegInfo* RI = E->RI;
210 /* Check for the call */
211 if (CE_IsCallTo (E, "steaxysp") &&
212 RegValIsKnown (RI->In.RegA) &&
213 RegValIsKnown (RI->In.RegX) &&
214 RegValIsKnown (RI->In.RegY) &&
215 RegValIsKnown (RI->In.SRegLo) &&
216 RegValIsKnown (RI->In.SRegHi) &&
217 !RegEAXUsed (S, I+1)) {
219 /* Get the register values */
220 unsigned char A = RI->In.RegA;
221 unsigned char X = RI->In.RegX;
222 unsigned char Y = RI->In.RegY;
223 unsigned char L = RI->In.SRegLo;
224 unsigned char H = RI->In.SRegHi;
226 /* Setup other variables */
229 unsigned IP = I + 1; /* Insertion point */
231 /* Replace the store. We will not remove the loads, since this is
232 * too complex and will be done by other optimizer steps.
234 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
235 CS_InsertEntry (S, N, IP++);
236 InsertStore (S, &IP, E->LI);
239 /* Check if we can store one of the other bytes */
240 if (A == X && (Done & 0x02) == 0) {
241 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
242 CS_InsertEntry (S, N, IP++);
243 InsertStore (S, &IP, E->LI);
246 if (A == L && (Done & 0x04) == 0) {
247 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
248 CS_InsertEntry (S, N, IP++);
249 InsertStore (S, &IP, E->LI);
252 if (A == H && (Done & 0x08) == 0) {
253 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
254 CS_InsertEntry (S, N, IP++);
255 InsertStore (S, &IP, E->LI);
259 /* Store the second byte */
260 if ((Done & 0x02) == 0) {
261 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
262 CS_InsertEntry (S, N, IP++);
263 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI);
264 CS_InsertEntry (S, N, IP++);
265 InsertStore (S, &IP, E->LI);
269 /* Check if we can store one of the other bytes */
270 if (X == L && (Done & 0x04) == 0) {
271 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
272 CS_InsertEntry (S, N, IP++);
273 InsertStore (S, &IP, E->LI);
276 if (X == H && (Done & 0x08) == 0) {
277 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
278 CS_InsertEntry (S, N, IP++);
279 InsertStore (S, &IP, E->LI);
283 /* Store the third byte */
284 if ((Done & 0x04) == 0) {
285 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI);
286 CS_InsertEntry (S, N, IP++);
287 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI);
288 CS_InsertEntry (S, N, IP++);
289 InsertStore (S, &IP, E->LI);
293 /* Check if we can store one of the other bytes */
294 if (L == H && (Done & 0x08) == 0) {
295 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
296 CS_InsertEntry (S, N, IP++);
297 InsertStore (S, &IP, E->LI);
301 /* Store the fourth byte */
302 if ((Done & 0x08) == 0) {
303 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI);
304 CS_InsertEntry (S, N, IP++);
305 N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI);
306 CS_InsertEntry (S, N, IP++);
307 InsertStore (S, &IP, E->LI);
311 /* Remove the call */
314 /* Remember, we had changes */
324 /* Free the register info */
327 /* Return the number of changes made */
333 unsigned OptStore4 (CodeSeg* S)
334 /* Search for the sequence
341 * and remove the useless load, provided that the next insn doesn't use flags
345 unsigned Changes = 0;
347 /* Walk over the entries */
349 while (I < CS_GetEntryCount (S)) {
354 L[0] = CS_GetEntry (S, I);
356 /* Check for the sequence */
357 if (L[0]->OPC == OP65_STA &&
358 (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP) &&
359 !CS_RangeHasLabel (S, I+1, 3) &&
360 CS_GetEntries (S, L+1, I+1, 4) &&
361 L[1]->OPC == OP65_STX &&
362 L[1]->AM == L[0]->AM &&
363 L[2]->OPC == OP65_LDA &&
364 L[2]->AM == L[0]->AM &&
365 L[3]->OPC == OP65_LDX &&
366 L[3]->AM == L[1]->AM &&
367 strcmp (L[0]->Arg, L[2]->Arg) == 0 &&
368 strcmp (L[1]->Arg, L[3]->Arg) == 0 &&
369 !CE_UseLoadFlags (L[4])) {
371 /* Register has already the correct value, remove the loads */
372 CS_DelEntries (S, I+2, 2);
374 /* Remember, we had changes */
384 /* Return the number of changes made */