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