]> git.sur5r.net Git - cc65/blob - src/cc65/coptneg.c
6aed9ccc2fbd9e54cb1e81d4c45856cce5881aaf
[cc65] / src / cc65 / coptneg.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptneg.c                                 */
4 /*                                                                           */
5 /*                        Optimize negation 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 /* cc65 */
37 #include "codeent.h"
38 #include "codeinfo.h"
39 #include "coptneg.h"
40
41
42
43 /*****************************************************************************/
44 /*                            nega optimizations                             */
45 /*****************************************************************************/
46
47
48
49 unsigned OptNegA1 (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_IsCall (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 OptNegA2 (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_IsCall (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 /*                            negax optimizations                            */
164 /*****************************************************************************/
165
166
167
168 unsigned OptNegAX1 (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             &&
189             CE_IsCall (E, "bnegax")) {
190
191             /* We're cheating somewhat here ... */
192             E->Arg[5] = '\0';
193             E->Use &= ~REG_X;
194
195             /* We had changes */
196             ++Changes;
197         }
198
199         /* Next entry */
200         ++I;
201
202     }
203
204     /* Free register info */
205     CS_FreeRegInfo (S);
206
207     /* Return the number of changes made */
208     return Changes;
209 }
210
211
212
213 unsigned OptNegAX2 (CodeSeg* S)
214 /* Search for the sequence:
215  *
216  *      lda     (xx),y
217  *      tax
218  *      dey
219  *      lda     (xx),y
220  *      jsr     bnegax
221  *      jne/jeq ...
222  *
223  * and replace it by
224  *
225  *      lda     (xx),y
226  *      dey
227  *      ora     (xx),y
228  *      jeq/jne ...
229  */
230 {
231     unsigned Changes = 0;
232
233     /* Walk over the entries */
234     unsigned I = 0;
235     while (I < CS_GetEntryCount (S)) {
236
237         CodeEntry* L[5];
238
239         /* Get next entry */
240         CodeEntry* E = CS_GetEntry (S, I);
241
242         /* Check for the sequence */
243         if (E->OPC == OP65_LDA                  &&
244             E->AM == AM65_ZP_INDY               &&
245             CS_GetEntries (S, L, I+1, 5)        &&
246             L[0]->OPC == OP65_TAX               &&
247             L[1]->OPC == OP65_DEY               &&
248             L[2]->OPC == OP65_LDA               &&
249             L[2]->AM == AM65_ZP_INDY            &&
250             strcmp (L[2]->Arg, E->Arg) == 0     &&
251             !CE_HasLabel (L[2])                 &&
252             CE_IsCall (L[3], "bnegax")          &&
253             !CE_HasLabel (L[3])                 &&
254             (L[4]->Info & OF_ZBRA) != 0         &&
255             !CE_HasLabel (L[4])) {
256
257             /* lda --> ora */
258             CE_ReplaceOPC (L[2], OP65_ORA);
259
260             /* Invert the branch */
261             CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
262
263             /* Delete the entries no longer needed. Beware: Deleting entries
264              * will change the indices.
265              */
266             CS_DelEntry (S, I+4);               /* jsr bnegax */
267             CS_DelEntry (S, I+1);               /* tax */
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 OptNegAX3 (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_IsCall (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 OptNegAX4 (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