]> git.sur5r.net Git - cc65/blob - src/cc65/coptstore.c
Renamed ExprDesc.Val to ExprDesc.IVal. Added an FVal field for a floating
[cc65] / src / cc65 / coptstore.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  coptstore.c                              */
4 /*                                                                           */
5 /*                                Optimize stores                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2003 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_KnownImm (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_KnownImm (L[2])                              &&
89             L[2]->Num == L[0]->Num + 1                      &&
90             CE_IsCallTo (L[3], "ldaxysp")                   &&
91             !CE_UseLoadFlags (L[4])) {
92
93             /* Register has already the correct value, remove the loads */
94             CS_DelEntries (S, I+2, 2);
95
96             /* Remember, we had changes */
97             ++Changes;
98
99         }
100
101         /* Next entry */
102         ++I;
103
104     }
105
106     /* Return the number of changes made */
107     return Changes;
108 }
109
110
111
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
115  * stack.
116  */
117 {
118     unsigned I;
119     unsigned Changes = 0;
120
121     /* Generate register info */
122     CS_GenRegInfo (S);
123
124     /* Walk over the entries */
125     I = 0;
126     while (I < CS_GetEntryCount (S)) {
127
128         /* Get next entry */
129         CodeEntry* E = CS_GetEntry (S, I);
130
131         /* Get the input registers */
132         const RegInfo* RI = E->RI;
133
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)) {
140
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;
145
146             /* Setup other variables */
147             CodeEntry*  N;
148             unsigned    IP = I + 1;     /* Insertion point */
149
150             /* Replace the store. We will not remove the loads, since this is
151              * too complex and will be done by other optimizer steps.
152              */
153             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
154             CS_InsertEntry (S, N, IP++);
155             InsertStore (S, &IP, E->LI);
156
157             /* Check if we can store one of the other bytes */
158             if (A != X) {
159                 N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI);
160                 CS_InsertEntry (S, N, IP++);
161             }
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);
165
166             /* Remove the call */
167             CS_DelEntry (S, I);
168
169             /* Remember, we had changes */
170             ++Changes;
171
172         }
173
174         /* Next entry */
175         ++I;
176
177     }
178
179     /* Free the register info */
180     CS_FreeRegInfo (S);
181
182     /* Return the number of changes made */
183     return Changes;
184 }
185
186
187
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
191  * stack.
192  */
193 {
194     unsigned I;
195     unsigned Changes = 0;
196
197     /* Generate register info */
198     CS_GenRegInfo (S);
199
200     /* Walk over the entries */
201     I = 0;
202     while (I < CS_GetEntryCount (S)) {
203
204         /* Get next entry */
205         CodeEntry* E = CS_GetEntry (S, I);
206
207         /* Get the input registers */
208         const RegInfo* RI = E->RI;
209
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)) {
218
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;
225
226             /* Setup other variables */
227             unsigned    Done = 0;
228             CodeEntry*  N;
229             unsigned    IP = I + 1;     /* Insertion point */
230
231             /* Replace the store. We will not remove the loads, since this is
232              * too complex and will be done by other optimizer steps.
233              */
234             N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI);
235             CS_InsertEntry (S, N, IP++);
236             InsertStore (S, &IP, E->LI);
237             Done |= 0x01;
238
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);
244                 Done |= 0x02;
245             }
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);
250                 Done |= 0x04;
251             }
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);
256                 Done |= 0x08;
257             }
258
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);
266                 Done |= 0x02;
267             }
268
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);
274                 Done |= 0x04;
275             }
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);
280                 Done |= 0x08;
281             }
282
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);
290                 Done |= 0x04;
291             }
292
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);
298                 Done |= 0x08;
299             }
300
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);
308                 Done |= 0x08;
309             }
310
311             /* Remove the call */
312             CS_DelEntry (S, I);
313
314             /* Remember, we had changes */
315             ++Changes;
316
317         }
318
319         /* Next entry */
320         ++I;
321
322     }
323
324     /* Free the register info */
325     CS_FreeRegInfo (S);
326
327     /* Return the number of changes made */
328     return Changes;
329 }
330
331
332
333 unsigned OptStore4 (CodeSeg* S)
334 /* Search for the sequence
335  *
336  *      sta     xx
337  *      stx     yy
338  *      lda     xx
339  *      ldx     yy
340  *
341  * and remove the useless load, provided that the next insn doesn't use flags
342  * from the load.
343  */
344 {
345     unsigned Changes = 0;
346
347     /* Walk over the entries */
348     unsigned I = 0;
349     while (I < CS_GetEntryCount (S)) {
350
351         CodeEntry* L[5];
352
353         /* Get next entry */
354         L[0] = CS_GetEntry (S, I);
355
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])) {
370
371             /* Register has already the correct value, remove the loads */
372             CS_DelEntries (S, I+2, 2);
373
374             /* Remember, we had changes */
375             ++Changes;
376
377         }
378
379         /* Next entry */
380         ++I;
381
382     }
383
384     /* Return the number of changes made */
385     return Changes;
386 }
387
388
389