]> git.sur5r.net Git - cc65/blob - src/cc65/coptstore.c
Allow for warning-free build of cc65 with MS VC on warning level 3.
[cc65] / src / cc65 / coptstore.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  coptstore.c                              */
4 /*                                                                           */
5 /*                                Optimize stores                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2012, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 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.
66  */
67 {
68     unsigned Changes = 0;
69
70     /* Walk over the entries */
71     unsigned I = 0;
72     while (I < CS_GetEntryCount (S)) {
73
74         CodeEntry* L[4];
75
76         /* Get next entry */
77         L[0] = CS_GetEntry (S, I);
78
79         /* Check for the sequence */
80         if (L[0]->OPC == OP65_LDY                           &&
81             CE_IsConstImm (L[0])                            &&
82             L[0]->Num < 0xFF                                &&
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")) {
89
90             /* Register has already the correct value, remove the loads */
91             CS_DelEntries (S, I+2, 2);
92
93             /* Remember, we had changes */
94             ++Changes;
95
96         }
97
98         /* Next entry */
99         ++I;
100
101     }
102
103     /* Return the number of changes made */
104     return Changes;
105 }
106
107
108
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
112  * stack.
113  */
114 {
115     unsigned I;
116     unsigned Changes = 0;
117
118     /* Walk over the entries */
119     I = 0;
120     while (I < CS_GetEntryCount (S)) {
121
122         /* Get next entry */
123         CodeEntry* E = CS_GetEntry (S, I);
124
125         /* Get the input registers */
126         const RegInfo* RI = E->RI;
127
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)) {
134
135             /* Get the register values */
136             unsigned char A = (unsigned char) RI->In.RegA;
137             unsigned char X = (unsigned char) RI->In.RegX;
138             unsigned char Y = (unsigned char) RI->In.RegY;
139
140             /* Setup other variables */
141             CodeEntry*  N;
142             unsigned    IP = I + 1;     /* Insertion point */
143
144             /* Replace the store. We will not remove the loads, since this is
145              * too complex and will be done by other optimizer steps.
146              */
147             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
148             CS_InsertEntry (S, N, IP++);
149             InsertStore (S, &IP, E->LI);
150
151             /* Check if we can store one of the other bytes */
152             if (A != X) {
153                 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
154                 CS_InsertEntry (S, N, IP++);
155             }
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);
159
160             /* Remove the call */
161             CS_DelEntry (S, I);
162
163             /* Remember, we had changes */
164             ++Changes;
165
166         }
167
168         /* Next entry */
169         ++I;
170
171     }
172
173     /* Return the number of changes made */
174     return Changes;
175 }
176
177
178
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
182  * stack.
183  */
184 {
185     unsigned I;
186     unsigned Changes = 0;
187
188     /* Walk over the entries */
189     I = 0;
190     while (I < CS_GetEntryCount (S)) {
191
192         /* Get next entry */
193         CodeEntry* E = CS_GetEntry (S, I);
194
195         /* Get the input registers */
196         const RegInfo* RI = E->RI;
197
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)) {
206
207             /* Get the register values */
208             unsigned char A = (unsigned char) RI->In.RegA;
209             unsigned char X = (unsigned char) RI->In.RegX;
210             unsigned char Y = (unsigned char) RI->In.RegY;
211             unsigned char L = (unsigned char) RI->In.SRegLo;
212             unsigned char H = (unsigned char) RI->In.SRegHi;
213
214             /* Setup other variables */
215             unsigned    Done = 0;
216             CodeEntry*  N;
217             unsigned    IP = I + 1;     /* Insertion point */
218
219             /* Replace the store. We will not remove the loads, since this is
220              * too complex and will be done by other optimizer steps.
221              */
222             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
223             CS_InsertEntry (S, N, IP++);
224             InsertStore (S, &IP, E->LI);
225             Done |= 0x01;
226
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);
232                 Done |= 0x02;
233             }
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);
238                 Done |= 0x04;
239             }
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);
244                 Done |= 0x08;
245             }
246
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);
254                 Done |= 0x02;
255             }
256
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);
262                 Done |= 0x04;
263             }
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);
268                 Done |= 0x08;
269             }
270
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);
278                 Done |= 0x04;
279             }
280
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);
286                 Done |= 0x08;
287             }
288
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);
296                 Done |= 0x08;
297             }
298
299             /* Remove the call */
300             CS_DelEntry (S, I);
301
302             /* Remember, we had changes */
303             ++Changes;
304
305         }
306
307         /* Next entry */
308         ++I;
309
310     }
311
312     /* Return the number of changes made */
313     return Changes;
314 }
315
316
317
318 unsigned OptStore4 (CodeSeg* S)
319 /* Search for the sequence
320  *
321  *      sta     xx
322  *      stx     yy
323  *      lda     xx
324  *      ldx     yy
325  *
326  * and remove the useless load, provided that the next insn doesn't use flags
327  * from the load.
328  */
329 {
330     unsigned Changes = 0;
331
332     /* Walk over the entries */
333     unsigned I = 0;
334     while (I < CS_GetEntryCount (S)) {
335
336         CodeEntry* L[5];
337
338         /* Get next entry */
339         L[0] = CS_GetEntry (S, I);
340
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])) {
355
356             /* Register has already the correct value, remove the loads */
357             CS_DelEntries (S, I+2, 2);
358
359             /* Remember, we had changes */
360             ++Changes;
361
362         }
363
364         /* Next entry */
365         ++I;
366
367     }
368
369     /* Return the number of changes made */
370     return Changes;
371 }
372
373
374
375 unsigned OptStore5 (CodeSeg* S)
376 /* Search for the sequence
377  *
378  *      lda     foo
379  *      ldx     bar
380  *      sta     something
381  *      stx     something-else
382  *
383  * and replace it by
384  *
385  *      lda     foo
386  *      sta     something
387  *      lda     bar
388  *      sta     something-else
389  *
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.
392  */
393 {
394     unsigned Changes = 0;
395
396     /* Walk over the entries */
397     unsigned I = 0;
398     while (I < CS_GetEntryCount (S)) {
399
400         CodeEntry* L[4];
401
402         /* Get next entry */
403         L[0] = CS_GetEntry (S, I);
404
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)) {
413
414             CodeEntry* X;
415
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);
421
422             /* Delete the old code */
423             CS_DelEntry (S, I+3);
424             CS_DelEntry (S, I+1);
425
426             /* Remember, we had changes */
427             ++Changes;
428         }
429
430         /* Next entry */
431         ++I;
432
433     }
434
435     /* Return the number of changes made */
436     return Changes;
437 }
438
439
440