]> git.sur5r.net Git - cc65/blob - src/cc65/coptstore.c
b738c38dba02ab924b51f7acae33ee7382f0fc02
[cc65] / src / cc65 / coptstore.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  coptstore.c                              */
4 /*                                                                           */
5 /*                                Optimize stores                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2005, Ullrich von Bassewitz                                      */
10 /*                Römerstrasse 52                                            */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 /* cc65 */
37 #include "codeent.h"
38 #include "codeinfo.h"
39 #include "coptstore.h"
40
41
42
43 /*****************************************************************************/
44 /*                                   Code                                    */
45 /*****************************************************************************/
46
47
48
49 static void InsertStore (CodeSeg* S, unsigned* IP, LineInfo* LI)
50 {
51     CodeEntry* X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, LI);
52     CS_InsertEntry (S, X, (*IP)++);
53 }
54
55
56
57 unsigned OptStore1 (CodeSeg* S)
58 /* Search for the sequence
59  *
60  *      ldy     #n
61  *      jsr     staxysp
62  *      ldy     #n+1
63  *      jsr     ldaxysp
64  *
65  * and remove the useless load, provided that the next insn doesn't use flags
66  * from the load.
67  */
68 {
69     unsigned Changes = 0;
70
71     /* Walk over the entries */
72     unsigned I = 0;
73     while (I < CS_GetEntryCount (S)) {
74
75         CodeEntry* L[5];
76
77         /* Get next entry */
78         L[0] = CS_GetEntry (S, I);
79
80         /* Check for the sequence */
81         if (L[0]->OPC == OP65_LDY                           &&
82             CE_IsConstImm (L[0])                            &&
83             L[0]->Num < 0xFF                                &&
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])) {
91
92             /* Register has already the correct value, remove the loads */
93             CS_DelEntries (S, I+2, 2);
94
95             /* Remember, we had changes */
96             ++Changes;
97
98         }
99
100         /* Next entry */
101         ++I;
102
103     }
104
105     /* Return the number of changes made */
106     return Changes;
107 }
108
109
110
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
114  * stack.
115  */
116 {
117     unsigned I;
118     unsigned Changes = 0;
119
120     /* Generate register info */
121     CS_GenRegInfo (S);
122
123     /* Walk over the entries */
124     I = 0;
125     while (I < CS_GetEntryCount (S)) {
126
127         /* Get next entry */
128         CodeEntry* E = CS_GetEntry (S, I);
129
130         /* Get the input registers */
131         const RegInfo* RI = E->RI;
132
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)) {
139
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;
144
145             /* Setup other variables */
146             CodeEntry*  N;
147             unsigned    IP = I + 1;     /* Insertion point */
148
149             /* Replace the store. We will not remove the loads, since this is
150              * too complex and will be done by other optimizer steps.
151              */
152             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
153             CS_InsertEntry (S, N, IP++);
154             InsertStore (S, &IP, E->LI);
155
156             /* Check if we can store one of the other bytes */
157             if (A != X) {
158                 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
159                 CS_InsertEntry (S, N, IP++);
160             }
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);
164
165             /* Remove the call */
166             CS_DelEntry (S, I);
167
168             /* Remember, we had changes */
169             ++Changes;
170
171         }
172
173         /* Next entry */
174         ++I;
175
176     }
177
178     /* Free the register info */
179     CS_FreeRegInfo (S);
180
181     /* Return the number of changes made */
182     return Changes;
183 }
184
185
186
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
190  * stack.
191  */
192 {
193     unsigned I;
194     unsigned Changes = 0;
195
196     /* Generate register info */
197     CS_GenRegInfo (S);
198
199     /* Walk over the entries */
200     I = 0;
201     while (I < CS_GetEntryCount (S)) {
202
203         /* Get next entry */
204         CodeEntry* E = CS_GetEntry (S, I);
205
206         /* Get the input registers */
207         const RegInfo* RI = E->RI;
208
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)) {
217
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;
224
225             /* Setup other variables */
226             unsigned    Done = 0;
227             CodeEntry*  N;
228             unsigned    IP = I + 1;     /* Insertion point */
229
230             /* Replace the store. We will not remove the loads, since this is
231              * too complex and will be done by other optimizer steps.
232              */
233             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
234             CS_InsertEntry (S, N, IP++);
235             InsertStore (S, &IP, E->LI);
236             Done |= 0x01;
237
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);
243                 Done |= 0x02;
244             }
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);
249                 Done |= 0x04;
250             }
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);
255                 Done |= 0x08;
256             }
257
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);
265                 Done |= 0x02;
266             }
267
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);
273                 Done |= 0x04;
274             }
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);
279                 Done |= 0x08;
280             }
281
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);
289                 Done |= 0x04;
290             }
291
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);
297                 Done |= 0x08;
298             }
299
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);
307                 Done |= 0x08;
308             }
309
310             /* Remove the call */
311             CS_DelEntry (S, I);
312
313             /* Remember, we had changes */
314             ++Changes;
315
316         }
317
318         /* Next entry */
319         ++I;
320
321     }
322
323     /* Free the register info */
324     CS_FreeRegInfo (S);
325
326     /* Return the number of changes made */
327     return Changes;
328 }
329
330
331
332 unsigned OptStore4 (CodeSeg* S)
333 /* Search for the sequence
334  *
335  *      sta     xx
336  *      stx     yy
337  *      lda     xx
338  *      ldx     yy
339  *
340  * and remove the useless load, provided that the next insn doesn't use flags
341  * from the load.
342  */
343 {
344     unsigned Changes = 0;
345
346     /* Walk over the entries */
347     unsigned I = 0;
348     while (I < CS_GetEntryCount (S)) {
349
350         CodeEntry* L[5];
351
352         /* Get next entry */
353         L[0] = CS_GetEntry (S, I);
354
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])) {
369
370             /* Register has already the correct value, remove the loads */
371             CS_DelEntries (S, I+2, 2);
372
373             /* Remember, we had changes */
374             ++Changes;
375
376         }
377
378         /* Next entry */
379         ++I;
380
381     }
382
383     /* Return the number of changes made */
384     return Changes;
385 }
386
387
388