]> git.sur5r.net Git - cc65/blob - src/cc65/coptadd.c
49c966ce9f71c7c7e967e51da436c3ef2648095f
[cc65] / src / cc65 / coptadd.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptadd.c                                 */
4 /*                                                                           */
5 /*                        Optimize addition sequences                        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 #include <string.h>
37
38 /* common */
39 #include "xsprintf.h"
40
41 /* cc65 */
42 #include "codeent.h"
43 #include "codeinfo.h"
44 #include "coptadd.h"
45
46
47
48 /*****************************************************************************/
49 /*                            Optimize additions                             */
50 /*****************************************************************************/
51
52
53
54 unsigned OptAdd1 (CodeSeg* S)
55 /* Search for the sequence
56  *
57  *      jsr     pushax
58  *      ldy     xxx
59  *      ldx     #$00
60  *      lda     (sp),y
61  *      jsr     tosaddax
62  *
63  * and replace it by:
64  *
65  *      ldy     xxx-2
66  *      clc
67  *      adc     (sp),y
68  *      bcc     L
69  *      inx
70  * L:
71  */
72 {
73     unsigned Changes = 0;
74
75     /* Walk over the entries */
76     unsigned I = 0;
77     while (I < CS_GetEntryCount (S)) {
78
79         CodeEntry* L[5];
80
81         /* Get next entry */
82         CodeEntry* E = CS_GetEntry (S, I);
83
84         /* Check for the sequence */
85         if (E->OPC == OP65_JSR                               &&
86             strcmp (E->Arg, "pushax") == 0                   &&
87             CS_GetEntries (S, L, I+1, 5)                     &&
88             L[0]->OPC == OP65_LDY                            &&
89             CE_KnownImm (L[0])                               &&
90             !CE_HasLabel (L[0])                              &&
91             L[1]->OPC == OP65_LDX                            &&
92             CE_KnownImm (L[1])                               &&
93             L[1]->Num == 0                                   &&
94             !CE_HasLabel (L[1])                              &&
95             L[2]->OPC == OP65_LDA                            &&
96             !CE_HasLabel (L[2])                              &&
97             L[3]->OPC == OP65_JSR                            &&
98             strcmp (L[3]->Arg, "tosaddax") == 0              &&
99             !CE_HasLabel (L[3])) {
100
101             CodeEntry* X;
102             CodeLabel* Label;
103
104             /* Remove the call to pushax */
105             CS_DelEntry (S, I);
106
107             /* Correct the stack offset (needed since pushax was removed) */
108             CE_SetNumArg (L[0], L[0]->Num - 2);
109
110             /* Add the clc . */
111             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
112             CS_InsertEntry (S, X, I+1);
113
114             /* Remove the load */
115             CS_DelEntry (S, I+3);      /* lda */
116             CS_DelEntry (S, I+2);      /* ldx */
117
118             /* Add the adc */
119             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
120             CS_InsertEntry (S, X, I+2);
121
122             /* Generate the branch label and the branch */
123             Label = CS_GenLabel (S, L[4]);
124             X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI);
125             CS_InsertEntry (S, X, I+3);
126
127             /* Generate the increment of the high byte */
128             X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI);
129             CS_InsertEntry (S, X, I+4);
130
131             /* Delete the call to tosaddax */
132             CS_DelEntry (S, I+5);
133
134             /* Remember, we had changes */
135             ++Changes;
136
137         }
138
139         /* Next entry */
140         ++I;
141
142     }
143
144     /* Return the number of changes made */
145     return Changes;
146 }
147
148
149
150 unsigned OptAdd2 (CodeSeg* S)
151 /* Search for the sequence
152  *
153  *      ldy     #xx
154  *      lda     (sp),y
155  *      tax
156  *      dey
157  *      lda     (sp),y
158  *      ldy     #$yy
159  *      jsr     addeqysp
160  *
161  * and replace it by:
162  *
163  *      ldy     #xx-1
164  *      lda     (sp),y
165  *      ldy     #yy
166  *      clc
167  *      adc     (sp),y
168  *      sta     (sp),y
169  *      ldy     #xx
170  *      lda     (sp),y
171  *      ldy     #yy+1
172  *      adc     (sp),y
173  *      sta     (sp),y
174  *
175  * provided that a/x is not used later.
176  */
177 {
178     unsigned Changes = 0;
179
180     /* Walk over the entries */
181     unsigned I = 0;
182     while (I < CS_GetEntryCount (S)) {
183
184         CodeEntry* L[7];
185
186         /* Get next entry */
187         L[0] = CS_GetEntry (S, I);
188
189         /* Check for the sequence */
190         if (L[0]->OPC == OP65_LDY               &&
191             CE_KnownImm (L[0])                  &&
192             CS_GetEntries (S, L+1, I+1, 6)      &&
193             L[1]->OPC == OP65_LDA               &&
194             L[1]->AM == AM65_ZP_INDY            &&
195             !CE_HasLabel (L[1])                 &&
196             L[2]->OPC == OP65_TAX               &&
197             !CE_HasLabel (L[2])                 &&
198             L[3]->OPC == OP65_DEY               &&
199             !CE_HasLabel (L[3])                 &&
200             L[4]->OPC == OP65_LDA               &&
201             L[4]->AM == AM65_ZP_INDY            &&
202             !CE_HasLabel (L[4])                 &&
203             L[5]->OPC == OP65_LDY               &&
204             CE_KnownImm (L[5])                  &&
205             !CE_HasLabel (L[5])                 &&
206             L[6]->OPC == OP65_JSR               &&
207             strcmp (L[6]->Arg, "addeqysp") == 0 &&
208             !CE_HasLabel (L[6])                 &&
209             (GetRegInfo (S, I+7, REG_AX) & REG_AX) == 0) {
210
211             char Buf [20];
212             CodeEntry* X;
213
214
215             /* Adjust the operand of the first LDY */
216             CE_SetNumArg (L[0], L[0]->Num - 1);
217
218             /* Load Y with the low offset of the target variable */
219             X = NewCodeEntry (OP65_LDY, AM65_IMM, L[5]->Arg, 0, L[1]->LI);
220             CS_InsertEntry (S, X, I+2);
221
222             /* Add the CLC */
223             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI);
224             CS_InsertEntry (S, X, I+3);
225
226             /* Remove the TAX/DEY sequence */
227             CS_DelEntry (S, I+5);      /* dey */
228             CS_DelEntry (S, I+4);      /* tax */
229
230             /* Addition of the low byte */
231             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[4]->LI);
232             CS_InsertEntry (S, X, I+4);
233             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[4]->LI);
234             CS_InsertEntry (S, X, I+5);
235
236             /* LDY */
237             xsprintf (Buf, sizeof (Buf), "$%02X", (int) (L[0]->Num+1));
238             X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[4]->LI);
239             CS_InsertEntry (S, X, I+6);
240
241             /* Addition of the high byte */
242             xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[5]->Num+1));
243             X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[5]->LI);
244             CS_InsertEntry (S, X, I+8);
245             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[6]->LI);
246             CS_InsertEntry (S, X, I+9);
247             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[6]->LI);
248             CS_InsertEntry (S, X, I+10);
249
250             /* Delete the remaining stuff */
251             CS_DelEntry (S, I+12);
252             CS_DelEntry (S, I+11);
253
254             /* Remember, we had changes */
255             ++Changes;
256
257         }
258
259         /* Next entry */
260         ++I;
261
262     }
263
264     /* Return the number of changes made */
265     return Changes;
266 }
267
268
269
270 unsigned OptAdd3 (CodeSeg* S)
271 /* Search for the sequence
272  *
273  *      adc     ...
274  *      bcc     L
275  *      inx
276  * L:
277  *
278  * and remove the handling of the high byte if X is not used later.
279  */
280 {
281     unsigned Changes = 0;
282
283     /* Walk over the entries */
284     unsigned I = 0;
285     while (I < CS_GetEntryCount (S)) {
286
287         CodeEntry* L[3];
288
289         /* Get next entry */
290         CodeEntry* E = CS_GetEntry (S, I);
291
292         /* Check for the sequence */
293         if (E->OPC == OP65_ADC                               &&
294             CS_GetEntries (S, L, I+1, 3)                     &&
295             (L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
296             L[0]->JumpTo != 0                                &&
297             !CE_HasLabel (L[0])                              &&
298             L[1]->OPC == OP65_INX                            &&
299             !CE_HasLabel (L[1])                              &&
300             L[0]->JumpTo->Owner == L[2]                      &&
301             !RegXUsed (S, I+3)) {
302
303             /* Remove the bcs/dex */
304             CS_DelEntries (S, I+1, 2);
305
306             /* Remember, we had changes */
307             ++Changes;
308
309         }
310
311         /* Next entry */
312         ++I;
313
314     }
315
316     /* Return the number of changes made */
317     return Changes;
318 }
319
320
321