]> git.sur5r.net Git - cc65/blob - src/cc65/coptneg.c
The OptNegXXX function were actually handling bnega... runtime stuff. Renamed
[cc65] / src / cc65 / coptneg.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptneg.c                                 */
4 /*                                                                           */
5 /*                        Optimize negation sequences                        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-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 "coptneg.h"
40
41
42
43 /*****************************************************************************/
44 /*                            bnega optimizations                            */
45 /*****************************************************************************/
46
47
48
49 unsigned OptBNegA1 (CodeSeg* S)
50 /* Check for
51  *
52  *      ldx     #$00
53  *      lda     ..
54  *      jsr     bnega
55  *
56  * Remove the ldx if the lda does not use it.
57  */
58 {
59     unsigned Changes = 0;
60
61     /* Walk over the entries */
62     unsigned I = 0;
63     while (I < CS_GetEntryCount (S)) {
64
65         CodeEntry* L[2];
66
67         /* Get next entry */
68         CodeEntry* E = CS_GetEntry (S, I);
69
70         /* Check for a ldx */
71         if (E->OPC == OP65_LDX                  &&
72             E->AM == AM65_IMM                   &&
73             (E->Flags & CEF_NUMARG) != 0        &&
74             E->Num == 0                         &&
75             CS_GetEntries (S, L, I+1, 2)        &&
76             L[0]->OPC == OP65_LDA               &&
77             (L[0]->Use & REG_X) == 0            &&
78             !CE_HasLabel (L[0])                 &&
79             CE_IsCallTo (L[1], "bnega")         &&
80             !CE_HasLabel (L[1])) {
81
82             /* Remove the ldx instruction */
83             CS_DelEntry (S, I);
84
85             /* Remember, we had changes */
86             ++Changes;
87
88         }
89
90         /* Next entry */
91         ++I;
92
93     }
94
95     /* Return the number of changes made */
96     return Changes;
97 }
98
99
100
101 unsigned OptBNegA2 (CodeSeg* S)
102 /* Check for
103  *
104  *      lda     ..
105  *      jsr     bnega
106  *      jeq/jne ..
107  *
108  * Adjust the conditional branch and remove the call to the subroutine.
109  */
110 {
111     unsigned Changes = 0;
112
113     /* Walk over the entries */
114     unsigned I = 0;
115     while (I < CS_GetEntryCount (S)) {
116
117         CodeEntry* L[2];
118
119         /* Get next entry */
120         CodeEntry* E = CS_GetEntry (S, I);
121
122         /* Check for the sequence */
123         if ((E->OPC == OP65_ADC ||
124              E->OPC == OP65_AND ||
125              E->OPC == OP65_DEA ||
126              E->OPC == OP65_EOR ||
127              E->OPC == OP65_INA ||
128              E->OPC == OP65_LDA ||
129              E->OPC == OP65_ORA ||
130              E->OPC == OP65_PLA ||
131              E->OPC == OP65_SBC ||
132              E->OPC == OP65_TXA ||
133              E->OPC == OP65_TYA)                &&
134             CS_GetEntries (S, L, I+1, 2)        &&
135             CE_IsCallTo (L[0], "bnega")         &&
136             !CE_HasLabel (L[0])                 &&
137             (L[1]->Info & OF_ZBRA) != 0         &&
138             !CE_HasLabel (L[1])) {
139
140             /* Invert the branch */
141             CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
142
143             /* Delete the subroutine call */
144             CS_DelEntry (S, I+1);
145
146             /* Remember, we had changes */
147             ++Changes;
148
149         }
150
151         /* Next entry */
152         ++I;
153
154     }
155
156     /* Return the number of changes made */
157     return Changes;
158 }
159
160
161
162 /*****************************************************************************/
163 /*                            bnegax optimizations                           */
164 /*****************************************************************************/
165
166
167
168 unsigned OptBNegAX1 (CodeSeg* S)
169 /* On a call to bnegax, if X is zero, the result depends only on the value in
170  * A, so change the call to a call to bnega. This will get further optimized
171  * later if possible.
172  */
173 {
174     unsigned Changes = 0;
175     unsigned I;
176
177     /* Generate register info for this step */
178     CS_GenRegInfo (S);
179
180     /* Walk over the entries */
181     I = 0;
182     while (I < CS_GetEntryCount (S)) {
183
184         /* Get next entry */
185         CodeEntry* E = CS_GetEntry (S, I);
186
187         /* Check if this is a call to bnegax, and if X is known and zero */
188         if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "bnegax")) {
189
190             CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI);
191             CS_InsertEntry (S, X, I+1);
192             CS_DelEntry (S, I);
193
194             /* We had changes */
195             ++Changes;
196         }
197
198         /* Next entry */
199         ++I;
200
201     }
202
203     /* Free register info */
204     CS_FreeRegInfo (S);
205
206     /* Return the number of changes made */
207     return Changes;
208 }
209
210
211
212 unsigned OptBNegAX2 (CodeSeg* S)
213 /* Search for the sequence:
214  *
215  *      ldy     #xx
216  *      jsr     ldaxysp
217  *      jsr     bnegax
218  *      jne/jeq ...
219  *
220  * and replace it by
221  *
222  *      ldy     #xx
223  *      lda     (sp),y
224  *      dey
225  *      ora     (sp),y
226  *      jeq/jne ...
227  */
228 {
229     unsigned Changes = 0;
230
231     /* Walk over the entries */
232     unsigned I = 0;
233     while (I < CS_GetEntryCount (S)) {
234
235         CodeEntry* L[4];
236
237         /* Get next entry */
238         L[0] = CS_GetEntry (S, I);
239
240         /* Check for the sequence */
241         if (L[0]->OPC == OP65_LDY               &&
242             CE_IsConstImm (L[0])                &&
243             !CS_RangeHasLabel (S, I+1, 3)       &&
244             CS_GetEntries (S, L+1, I+1, 3)      &&
245             CE_IsCallTo (L[1], "ldaxysp")       &&
246             CE_IsCallTo (L[2], "bnegax")        &&
247             (L[3]->Info & OF_ZBRA) != 0) {
248
249             CodeEntry* X;
250
251             /* lda (sp),y */
252             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
253             CS_InsertEntry (S, X, I+1);
254
255             /* dey */
256             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI);
257             CS_InsertEntry (S, X, I+2);
258
259             /* ora (sp),y */
260             X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
261             CS_InsertEntry (S, X, I+3);
262
263             /* Invert the branch */
264             CE_ReplaceOPC (L[3], GetInverseBranch (L[3]->OPC));
265
266             /* Delete the entries no longer needed. */
267             CS_DelEntries (S, I+4, 2);
268
269             /* Remember, we had changes */
270             ++Changes;
271
272         }
273
274         /* Next entry */
275         ++I;
276
277     }
278
279     /* Return the number of changes made */
280     return Changes;
281 }
282
283
284
285 unsigned OptBNegAX3 (CodeSeg* S)
286 /* Search for the sequence:
287  *
288  *      lda     xx
289  *      ldx     yy
290  *      jsr     bnegax
291  *      jne/jeq ...
292  *
293  * and replace it by
294  *
295  *      lda     xx
296  *      ora     xx+1
297  *      jeq/jne ...
298  */
299 {
300     unsigned Changes = 0;
301
302     /* Walk over the entries */
303     unsigned I = 0;
304     while (I < CS_GetEntryCount (S)) {
305
306         CodeEntry* L[3];
307
308         /* Get next entry */
309         CodeEntry* E = CS_GetEntry (S, I);
310
311         /* Check for the sequence */
312         if (E->OPC == OP65_LDA                  &&
313             CS_GetEntries (S, L, I+1, 3)        &&
314             L[0]->OPC == OP65_LDX               &&
315             !CE_HasLabel (L[0])                 &&
316             CE_IsCallTo (L[1], "bnegax")        &&
317             !CE_HasLabel (L[1])                 &&
318             (L[2]->Info & OF_ZBRA) != 0         &&
319             !CE_HasLabel (L[2])) {
320
321             /* ldx --> ora */
322             CE_ReplaceOPC (L[0], OP65_ORA);
323
324             /* Invert the branch */
325             CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
326
327             /* Delete the subroutine call */
328             CS_DelEntry (S, I+2);
329
330             /* Remember, we had changes */
331             ++Changes;
332
333         }
334
335         /* Next entry */
336         ++I;
337
338     }
339
340     /* Return the number of changes made */
341     return Changes;
342 }
343
344
345
346 unsigned OptBNegAX4 (CodeSeg* S)
347 /* Search for the sequence:
348  *
349  *      jsr     xxx
350  *      jsr     bnega(x)
351  *      jeq/jne ...
352  *
353  * and replace it by:
354  *
355  *      jsr     xxx
356  *      <boolean test>
357  *      jne/jeq ...
358  */
359 {
360     unsigned Changes = 0;
361
362     /* Walk over the entries */
363     unsigned I = 0;
364     while (I < CS_GetEntryCount (S)) {
365
366         CodeEntry* L[2];
367
368         /* Get next entry */
369         CodeEntry* E = CS_GetEntry (S, I);
370
371         /* Check for the sequence */
372         if (E->OPC == OP65_JSR                  &&
373             CS_GetEntries (S, L, I+1, 2)        &&
374             L[0]->OPC == OP65_JSR               &&
375             strncmp (L[0]->Arg,"bnega",5) == 0  &&
376             !CE_HasLabel (L[0])                 &&
377             (L[1]->Info & OF_ZBRA) != 0         &&
378             !CE_HasLabel (L[1])) {
379
380             CodeEntry* X;
381
382             /* Check if we're calling bnega or bnegax */
383             int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
384
385             /* Insert apropriate test code */
386             if (ByteSized) {
387                 /* Test bytes */
388                 X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
389                 CS_InsertEntry (S, X, I+2);
390             } else {
391                 /* Test words */
392                 X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
393                 CS_InsertEntry (S, X, I+2);
394                 X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
395                 CS_InsertEntry (S, X, I+3);
396             }
397
398             /* Delete the subroutine call */
399             CS_DelEntry (S, I+1);
400
401             /* Invert the branch */
402             CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
403
404             /* Remember, we had changes */
405             ++Changes;
406
407         }
408
409         /* Next entry */
410         ++I;
411
412     }
413
414     /* Return the number of changes made */
415     return Changes;
416 }
417
418
419