1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* coptptrload.c */ |
4 | /* */ |
5 | /* Optimize loads through pointers */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2009 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 | #include <string.h> |
37 | |
38 | /* common */ |
39 | #include "xmalloc.h" |
40 | |
41 | /* cc65 */ |
42 | #include "codeent.h" |
43 | #include "codeinfo.h" |
44 | #include "coptptrload.h" |
45 | |
46 | |
47 | |
48 | /*****************************************************************************/ |
49 | /* Code */ |
50 | /*****************************************************************************/ |
51 | |
52 | |
53 | |
54 | unsigned OptPtrLoad1 (CodeSeg* S) |
55 | /* Search for the sequence: |
56 | ** |
57 | ** clc |
58 | ** adc xxx |
59 | ** tay |
60 | ** txa |
61 | ** adc yyy |
62 | ** tax |
63 | ** tya |
64 | ** ldy #$00 |
65 | ** jsr ldauidx |
66 | ** |
67 | ** and replace it by: |
68 | ** |
69 | ** sta ptr1 |
70 | ** txa |
71 | ** clc |
72 | ** adc yyy |
73 | ** sta ptr1+1 |
74 | ** ldy xxx |
75 | ** ldx #$00 |
76 | ** lda (ptr1),y |
77 | */ |
78 | { |
79 | unsigned Changes = 0; |
80 | |
81 | /* Walk over the entries */ |
82 | unsigned I = 0; |
83 | while (I < CS_GetEntryCount (S)) { |
84 | |
85 | CodeEntry* L[9]; |
86 | |
87 | /* Get next entry */ |
88 | L[0] = CS_GetEntry (S, I); |
89 | |
90 | /* Check for the sequence */ |
91 | if (L[0]->OPC == OP65_CLC && |
92 | CS_GetEntries (S, L+1, I+1, 8) && |
93 | L[1]->OPC == OP65_ADC && |
94 | (L[1]->AM == AM65_ABS || |
95 | L[1]->AM == AM65_ZP || |
96 | L[1]->AM == AM65_IMM) && |
97 | L[2]->OPC == OP65_TAY && |
98 | L[3]->OPC == OP65_TXA && |
99 | L[4]->OPC == OP65_ADC && |
100 | L[5]->OPC == OP65_TAX && |
101 | L[6]->OPC == OP65_TYA && |
102 | L[7]->OPC == OP65_LDY && |
103 | CE_IsKnownImm (L[7], 0) && |
104 | CE_IsCallTo (L[8], "ldauidx" ) && |
105 | !CS_RangeHasLabel (S, I+1, 8)) { |
106 | |
107 | CodeEntry* X; |
108 | CodeEntry* P; |
109 | |
110 | /* Track the insertion point */ |
111 | unsigned IP = I+9; |
112 | |
113 | /* sta ptr1 */ |
114 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[2]->LI); |
115 | CS_InsertEntry (S, X, IP++); |
116 | |
117 | /* If the instruction before the clc is a ldx, replace the |
118 | ** txa by an lda with the same location of the ldx. Otherwise |
119 | ** transfer the value in X to A. |
120 | */ |
121 | if ((P = CS_GetPrevEntry (S, I)) != 0 && |
122 | P->OPC == OP65_LDX && |
123 | !CE_HasLabel (P)) { |
124 | X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI); |
125 | } else { |
126 | X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI); |
127 | } |
128 | CS_InsertEntry (S, X, IP++); |
129 | |
130 | /* clc */ |
131 | X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[0]->LI); |
132 | CS_InsertEntry (S, X, IP++); |
133 | |
134 | /* adc yyy */ |
135 | X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI); |
136 | CS_InsertEntry (S, X, IP++); |
137 | |
138 | /* sta ptr1+1 */ |
139 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1" , 0, L[5]->LI); |
140 | CS_InsertEntry (S, X, IP++); |
141 | |
142 | /* ldy xxx */ |
143 | X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI); |
144 | CS_InsertEntry (S, X, IP++); |
145 | |
146 | /* ldx #$00 */ |
147 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[8]->LI); |
148 | CS_InsertEntry (S, X, IP++); |
149 | |
150 | /* lda (ptr1),y */ |
151 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[8]->LI); |
152 | CS_InsertEntry (S, X, IP++); |
153 | |
154 | /* Remove the old instructions */ |
155 | CS_DelEntries (S, I, 9); |
156 | |
157 | /* Remember, we had changes */ |
158 | ++Changes; |
159 | |
160 | } |
161 | |
162 | /* Next entry */ |
163 | ++I; |
164 | |
165 | } |
166 | |
167 | /* Return the number of changes made */ |
168 | return Changes; |
169 | } |
170 | |
171 | |
172 | |
173 | unsigned OptPtrLoad2 (CodeSeg* S) |
174 | /* Search for the sequence: |
175 | ** |
176 | ** adc xxx |
177 | ** pha |
178 | ** txa |
179 | ** iny |
180 | ** adc yyy |
181 | ** tax |
182 | ** pla |
183 | ** ldy |
184 | ** jsr ldauidx |
185 | ** |
186 | ** and replace it by: |
187 | ** |
188 | ** adc xxx |
189 | ** sta ptr1 |
190 | ** txa |
191 | ** iny |
192 | ** adc yyy |
193 | ** sta ptr1+1 |
194 | ** ldy |
195 | ** ldx #$00 |
196 | ** lda (ptr1),y |
197 | */ |
198 | { |
199 | unsigned Changes = 0; |
200 | |
201 | /* Walk over the entries */ |
202 | unsigned I = 0; |
203 | while (I < CS_GetEntryCount (S)) { |
204 | |
205 | CodeEntry* L[9]; |
206 | |
207 | /* Get next entry */ |
208 | L[0] = CS_GetEntry (S, I); |
209 | |
210 | /* Check for the sequence */ |
211 | if (L[0]->OPC == OP65_ADC && |
212 | CS_GetEntries (S, L+1, I+1, 8) && |
213 | L[1]->OPC == OP65_PHA && |
214 | L[2]->OPC == OP65_TXA && |
215 | L[3]->OPC == OP65_INY && |
216 | L[4]->OPC == OP65_ADC && |
217 | L[5]->OPC == OP65_TAX && |
218 | L[6]->OPC == OP65_PLA && |
219 | L[7]->OPC == OP65_LDY && |
220 | CE_IsCallTo (L[8], "ldauidx" ) && |
221 | !CS_RangeHasLabel (S, I+1, 8)) { |
222 | |
223 | CodeEntry* X; |
224 | |
225 | /* Store the low byte and remove the PHA instead */ |
226 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[0]->LI); |
227 | CS_InsertEntry (S, X, I+1); |
228 | |
229 | /* Store the high byte */ |
230 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1" , 0, L[4]->LI); |
231 | CS_InsertEntry (S, X, I+6); |
232 | |
233 | /* Load high and low byte */ |
234 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[6]->LI); |
235 | CS_InsertEntry (S, X, I+10); |
236 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[6]->LI); |
237 | CS_InsertEntry (S, X, I+11); |
238 | |
239 | /* Delete the old code */ |
240 | CS_DelEntry (S, I+12); /* jsr ldauidx */ |
241 | CS_DelEntry (S, I+8); /* pla */ |
242 | CS_DelEntry (S, I+7); /* tax */ |
243 | CS_DelEntry (S, I+2); /* pha */ |
244 | |
245 | /* Remember, we had changes */ |
246 | ++Changes; |
247 | |
248 | } |
249 | |
250 | /* Next entry */ |
251 | ++I; |
252 | |
253 | } |
254 | |
255 | /* Return the number of changes made */ |
256 | return Changes; |
257 | } |
258 | |
259 | |
260 | |
261 | unsigned OptPtrLoad3 (CodeSeg* S) |
262 | /* Search for the sequence: |
263 | ** |
264 | ** lda #<(label+0) |
265 | ** ldx #>(label+0) |
266 | ** clc |
267 | ** adc xxx |
268 | ** bcc L |
269 | ** inx |
270 | ** L: ldy #$00 |
271 | ** jsr ldauidx |
272 | ** |
273 | ** and replace it by: |
274 | ** |
275 | ** ldy xxx |
276 | ** ldx #$00 |
277 | ** lda label,y |
278 | */ |
279 | { |
280 | unsigned Changes = 0; |
281 | |
282 | /* Walk over the entries */ |
283 | unsigned I = 0; |
284 | while (I < CS_GetEntryCount (S)) { |
285 | |
286 | CodeEntry* L[8]; |
287 | unsigned Len; |
288 | |
289 | /* Get next entry */ |
290 | L[0] = CS_GetEntry (S, I); |
291 | |
292 | /* Check for the sequence */ |
293 | if (L[0]->OPC == OP65_LDA && |
294 | L[0]->AM == AM65_IMM && |
295 | CS_GetEntries (S, L+1, I+1, 7) && |
296 | L[1]->OPC == OP65_LDX && |
297 | L[1]->AM == AM65_IMM && |
298 | L[2]->OPC == OP65_CLC && |
299 | L[3]->OPC == OP65_ADC && |
300 | (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP) && |
301 | (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) && |
302 | L[4]->JumpTo != 0 && |
303 | L[4]->JumpTo->Owner == L[6] && |
304 | L[5]->OPC == OP65_INX && |
305 | L[6]->OPC == OP65_LDY && |
306 | CE_IsKnownImm (L[6], 0) && |
307 | CE_IsCallTo (L[7], "ldauidx" ) && |
308 | !CS_RangeHasLabel (S, I+1, 5) && |
309 | !CE_HasLabel (L[7]) && |
310 | /* Check the label last because this is quite costly */ |
311 | (Len = strlen (L[0]->Arg)) > 3 && |
312 | L[0]->Arg[0] == '<' && |
313 | L[0]->Arg[1] == '(' && |
314 | strlen (L[1]->Arg) == Len && |
315 | L[1]->Arg[0] == '>' && |
316 | memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) { |
317 | |
318 | CodeEntry* X; |
319 | char* Label; |
320 | |
321 | /* We will create all the new stuff behind the current one so |
322 | ** we keep the line references. |
323 | */ |
324 | X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI); |
325 | CS_InsertEntry (S, X, I+8); |
326 | |
327 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[0]->LI); |
328 | CS_InsertEntry (S, X, I+9); |
329 | |
330 | Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3); |
331 | Label[Len-3] = '\0'; |
332 | X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI); |
333 | CS_InsertEntry (S, X, I+10); |
334 | xfree (Label); |
335 | |
336 | /* Remove the old code */ |
337 | CS_DelEntries (S, I, 8); |
338 | |
339 | /* Remember, we had changes */ |
340 | ++Changes; |
341 | |
342 | } |
343 | |
344 | /* Next entry */ |
345 | ++I; |
346 | |
347 | } |
348 | |
349 | /* Return the number of changes made */ |
350 | return Changes; |
351 | } |
352 | |
353 | |
354 | |
355 | unsigned OptPtrLoad4 (CodeSeg* S) |
356 | /* Search for the sequence: |
357 | ** |
358 | ** lda #<(label+0) |
359 | ** ldx #>(label+0) |
360 | ** ldy #$xx |
361 | ** clc |
362 | ** adc (sp),y |
363 | ** bcc L |
364 | ** inx |
365 | ** L: ldy #$00 |
366 | ** jsr ldauidx |
367 | ** |
368 | ** and replace it by: |
369 | ** |
370 | ** ldy #$xx |
371 | ** lda (sp),y |
372 | ** tay |
373 | ** ldx #$00 |
374 | ** lda label,y |
375 | */ |
376 | { |
377 | unsigned Changes = 0; |
378 | |
379 | /* Walk over the entries */ |
380 | unsigned I = 0; |
381 | while (I < CS_GetEntryCount (S)) { |
382 | |
383 | CodeEntry* L[9]; |
384 | unsigned Len; |
385 | |
386 | /* Get next entry */ |
387 | L[0] = CS_GetEntry (S, I); |
388 | |
389 | /* Check for the sequence */ |
390 | if (L[0]->OPC == OP65_LDA && |
391 | L[0]->AM == AM65_IMM && |
392 | CS_GetEntries (S, L+1, I+1, 8) && |
393 | L[1]->OPC == OP65_LDX && |
394 | L[1]->AM == AM65_IMM && |
395 | !CE_HasLabel (L[1]) && |
396 | L[2]->OPC == OP65_LDY && |
397 | CE_IsConstImm (L[2]) && |
398 | !CE_HasLabel (L[2]) && |
399 | L[3]->OPC == OP65_CLC && |
400 | !CE_HasLabel (L[3]) && |
401 | L[4]->OPC == OP65_ADC && |
402 | L[4]->AM == AM65_ZP_INDY && |
403 | !CE_HasLabel (L[4]) && |
404 | (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) && |
405 | L[5]->JumpTo != 0 && |
406 | L[5]->JumpTo->Owner == L[7] && |
407 | !CE_HasLabel (L[5]) && |
408 | L[6]->OPC == OP65_INX && |
409 | !CE_HasLabel (L[6]) && |
410 | L[7]->OPC == OP65_LDY && |
411 | CE_IsKnownImm (L[7], 0) && |
412 | CE_IsCallTo (L[8], "ldauidx" ) && |
413 | !CE_HasLabel (L[8]) && |
414 | /* Check the label last because this is quite costly */ |
415 | (Len = strlen (L[0]->Arg)) > 3 && |
416 | L[0]->Arg[0] == '<' && |
417 | L[0]->Arg[1] == '(' && |
418 | strlen (L[1]->Arg) == Len && |
419 | L[1]->Arg[0] == '>' && |
420 | memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) { |
421 | |
422 | CodeEntry* X; |
423 | char* Label; |
424 | |
425 | /* Add the lda */ |
426 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI); |
427 | CS_InsertEntry (S, X, I+3); |
428 | |
429 | /* Add the tay */ |
430 | X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI); |
431 | CS_InsertEntry (S, X, I+4); |
432 | |
433 | /* Add the ldx */ |
434 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[0]->LI); |
435 | CS_InsertEntry (S, X, I+5); |
436 | |
437 | /* Add the lda */ |
438 | Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3); |
439 | Label[Len-3] = '\0'; |
440 | X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI); |
441 | CS_InsertEntry (S, X, I+6); |
442 | xfree (Label); |
443 | |
444 | /* Remove the old code */ |
445 | CS_DelEntries (S, I, 2); |
446 | CS_DelEntries (S, I+5, 6); |
447 | |
448 | /* Remember, we had changes */ |
449 | ++Changes; |
450 | |
451 | } |
452 | |
453 | /* Next entry */ |
454 | ++I; |
455 | |
456 | } |
457 | |
458 | /* Return the number of changes made */ |
459 | return Changes; |
460 | } |
461 | |
462 | |
463 | |
464 | unsigned OptPtrLoad5 (CodeSeg* S) |
465 | /* Search for the sequence: |
466 | ** |
467 | ** jsr pushax |
468 | ** ldx #$00 |
469 | ** lda yyy |
470 | ** jsr tosaddax |
471 | ** ldy #$00 |
472 | ** jsr ldauidx |
473 | ** |
474 | ** and replace it by: |
475 | ** |
476 | ** sta ptr1 |
477 | ** stx ptr1+1 |
478 | ** ldy yyy |
479 | ** ldx #$00 |
480 | ** lda (ptr1),y |
481 | */ |
482 | { |
483 | unsigned Changes = 0; |
484 | |
485 | /* Walk over the entries */ |
486 | unsigned I = 0; |
487 | while (I < CS_GetEntryCount (S)) { |
488 | |
489 | CodeEntry* L[6]; |
490 | |
491 | /* Get next entry */ |
492 | L[0] = CS_GetEntry (S, I); |
493 | |
494 | /* Check for the sequence */ |
495 | if (CE_IsCallTo (L[0], "pushax" ) && |
496 | CS_GetEntries (S, L+1, I+1, 5) && |
497 | L[1]->OPC == OP65_LDX && |
498 | CE_IsKnownImm (L[1], 0) && |
499 | L[2]->OPC == OP65_LDA && |
500 | (L[2]->AM == AM65_ABS || |
501 | L[2]->AM == AM65_ZP || |
502 | L[2]->AM == AM65_IMM) && |
503 | CE_IsCallTo (L[3], "tosaddax" ) && |
504 | L[4]->OPC == OP65_LDY && |
505 | CE_IsKnownImm (L[4], 0) && |
506 | CE_IsCallTo (L[5], "ldauidx" ) && |
507 | !CS_RangeHasLabel (S, I+1, 5)) { |
508 | |
509 | CodeEntry* X; |
510 | |
511 | /* sta ptr1 */ |
512 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[0]->LI); |
513 | CS_InsertEntry (S, X, I+6); |
514 | |
515 | /* stx ptr1+1 */ |
516 | X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1" , 0, L[0]->LI); |
517 | CS_InsertEntry (S, X, I+7); |
518 | |
519 | /* ldy yyy */ |
520 | X = NewCodeEntry (OP65_LDY, L[2]->AM, L[2]->Arg, 0, L[2]->LI); |
521 | CS_InsertEntry (S, X, I+8); |
522 | |
523 | /* ldx #$00 */ |
524 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[5]->LI); |
525 | CS_InsertEntry (S, X, I+9); |
526 | |
527 | /* lda (ptr1),y */ |
528 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[5]->LI); |
529 | CS_InsertEntry (S, X, I+10); |
530 | |
531 | /* Remove the old code */ |
532 | CS_DelEntries (S, I, 6); |
533 | |
534 | /* Remember, we had changes */ |
535 | ++Changes; |
536 | |
537 | } |
538 | |
539 | /* Next entry */ |
540 | ++I; |
541 | |
542 | } |
543 | |
544 | /* Return the number of changes made */ |
545 | return Changes; |
546 | } |
547 | |
548 | |
549 | |
550 | unsigned OptPtrLoad6 (CodeSeg* S) |
551 | /* Search for the sequence: |
552 | ** |
553 | ** jsr pushax |
554 | ** ldy #xxx |
555 | ** ldx #$00 |
556 | ** lda (sp),y |
557 | ** jsr tosaddax |
558 | ** ldy #$00 |
559 | ** jsr ldauidx |
560 | ** |
561 | ** and replace it by: |
562 | ** |
563 | ** sta ptr1 |
564 | ** stx ptr1+1 |
565 | ** ldy #xxx-2 |
566 | ** lda (sp),y |
567 | ** tay |
568 | ** ldx #$00 |
569 | ** lda (ptr1),y |
570 | */ |
571 | { |
572 | unsigned Changes = 0; |
573 | |
574 | /* Walk over the entries */ |
575 | unsigned I = 0; |
576 | while (I < CS_GetEntryCount (S)) { |
577 | |
578 | CodeEntry* L[7]; |
579 | |
580 | /* Get next entry */ |
581 | L[0] = CS_GetEntry (S, I); |
582 | |
583 | /* Check for the sequence */ |
584 | if (CE_IsCallTo (L[0], "pushax" ) && |
585 | CS_GetEntries (S, L+1, I+1, 6) && |
586 | L[1]->OPC == OP65_LDY && |
587 | CE_IsConstImm (L[1]) && |
588 | L[1]->Num >= 2 && |
589 | L[2]->OPC == OP65_LDX && |
590 | CE_IsKnownImm (L[2], 0) && |
591 | L[3]->OPC == OP65_LDA && |
592 | L[3]->AM == AM65_ZP_INDY && |
593 | CE_IsCallTo (L[4], "tosaddax" ) && |
594 | L[5]->OPC == OP65_LDY && |
595 | CE_IsKnownImm (L[5], 0) && |
596 | CE_IsCallTo (L[6], "ldauidx" ) && |
597 | !CS_RangeHasLabel (S, I+1, 6) && |
598 | !RegYUsed (S, I+7)) { |
599 | |
600 | CodeEntry* X; |
601 | const char* Arg; |
602 | |
603 | /* sta ptr1 */ |
604 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[0]->LI); |
605 | CS_InsertEntry (S, X, I+7); |
606 | |
607 | /* stx ptr1+1 */ |
608 | X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1" , 0, L[0]->LI); |
609 | CS_InsertEntry (S, X, I+8); |
610 | |
611 | /* ldy #xxx-2 */ |
612 | Arg = MakeHexArg (L[1]->Num - 2); |
613 | X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI); |
614 | CS_InsertEntry (S, X, I+9); |
615 | |
616 | /* lda (sp),y */ |
617 | X = NewCodeEntry (OP65_LDA, L[3]->AM, L[3]->Arg, 0, L[3]->LI); |
618 | CS_InsertEntry (S, X, I+10); |
619 | |
620 | /* tay */ |
621 | X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[3]->LI); |
622 | CS_InsertEntry (S, X, I+11); |
623 | |
624 | /* ldx #$00 */ |
625 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[5]->LI); |
626 | CS_InsertEntry (S, X, I+12); |
627 | |
628 | /* lda (ptr1),y */ |
629 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[6]->LI); |
630 | CS_InsertEntry (S, X, I+13); |
631 | |
632 | /* Remove the old code */ |
633 | CS_DelEntries (S, I, 7); |
634 | |
635 | /* Remember, we had changes */ |
636 | ++Changes; |
637 | |
638 | } |
639 | |
640 | /* Next entry */ |
641 | ++I; |
642 | |
643 | } |
644 | |
645 | /* Return the number of changes made */ |
646 | return Changes; |
647 | } |
648 | |
649 | |
650 | |
651 | unsigned OptPtrLoad7 (CodeSeg* S) |
652 | /* Search for the sequence: |
653 | ** |
654 | ** jsr aslax1/shlax1 |
655 | ** clc |
656 | ** adc xxx |
657 | ** tay |
658 | ** txa |
659 | ** adc yyy |
660 | ** tax |
661 | ** tya |
662 | ** ldy zzz |
663 | ** jsr ldaxidx |
664 | ** |
665 | ** and replace it by: |
666 | ** |
667 | ** stx tmp1 |
668 | ** asl a |
669 | ** rol tmp1 |
670 | ** clc |
671 | ** adc xxx |
672 | ** sta ptr1 |
673 | ** lda tmp1 |
674 | ** adc yyy |
675 | ** sta ptr1+1 |
676 | ** ldy zzz |
677 | ** lda (ptr1),y |
678 | ** tax |
679 | ** dey |
680 | ** lda (ptr1),y |
681 | */ |
682 | { |
683 | unsigned Changes = 0; |
684 | unsigned I; |
685 | |
686 | /* Walk over the entries */ |
687 | I = 0; |
688 | while (I < CS_GetEntryCount (S)) { |
689 | |
690 | CodeEntry* L[10]; |
691 | |
692 | /* Get next entry */ |
693 | L[0] = CS_GetEntry (S, I); |
694 | |
695 | /* Check for the sequence */ |
696 | if (L[0]->OPC == OP65_JSR && |
697 | (strcmp (L[0]->Arg, "aslax1" ) == 0 || |
698 | strcmp (L[0]->Arg, "shlax1" ) == 0) && |
699 | CS_GetEntries (S, L+1, I+1, 9) && |
700 | L[1]->OPC == OP65_CLC && |
701 | L[2]->OPC == OP65_ADC && |
702 | L[3]->OPC == OP65_TAY && |
703 | L[4]->OPC == OP65_TXA && |
704 | L[5]->OPC == OP65_ADC && |
705 | L[6]->OPC == OP65_TAX && |
706 | L[7]->OPC == OP65_TYA && |
707 | L[8]->OPC == OP65_LDY && |
708 | CE_IsCallTo (L[9], "ldaxidx" ) && |
709 | !CS_RangeHasLabel (S, I+1, 9)) { |
710 | |
711 | CodeEntry* X; |
712 | |
713 | /* Track the insertion point */ |
714 | unsigned IP = I + 10; |
715 | |
716 | |
717 | /* If X is zero on entry to aslax1, we can generate: |
718 | ** |
719 | ** asl a |
720 | ** bcc L1 |
721 | ** inx |
722 | ** L1: clc |
723 | ** |
724 | ** instead of the code above. "lda tmp1" needs to be changed |
725 | ** to "txa" in this case. |
726 | */ |
727 | int ShortCode = (L[0]->RI->In.RegX == 0); |
728 | |
729 | if (ShortCode) { |
730 | |
731 | CodeLabel* Lab; |
732 | |
733 | /* asl a */ |
734 | X = NewCodeEntry (OP65_ASL, AM65_ACC, "a" , 0, L[0]->LI); |
735 | CS_InsertEntry (S, X, IP++); |
736 | |
737 | /* Generate clc first, since we need the label */ |
738 | X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI); |
739 | CS_InsertEntry (S, X, IP); |
740 | |
741 | /* Get the label */ |
742 | Lab = CS_GenLabel (S, X); |
743 | |
744 | /* bcc Lab */ |
745 | X = NewCodeEntry (OP65_BCC, AM65_BRA, Lab->Name, Lab, L[0]->LI); |
746 | CS_InsertEntry (S, X, IP++); |
747 | |
748 | /* inx */ |
749 | X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[0]->LI); |
750 | CS_InsertEntry (S, X, IP++); |
751 | |
752 | /* Skip the clc insn */ |
753 | ++IP; |
754 | |
755 | } else { |
756 | |
757 | /* stx tmp1 */ |
758 | X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1" , 0, L[0]->LI); |
759 | CS_InsertEntry (S, X, IP++); |
760 | |
761 | /* asl a */ |
762 | X = NewCodeEntry (OP65_ASL, AM65_ACC, "a" , 0, L[0]->LI); |
763 | CS_InsertEntry (S, X, IP++); |
764 | |
765 | /* rol tmp1 */ |
766 | X = NewCodeEntry (OP65_ROL, AM65_ZP, "tmp1" , 0, L[0]->LI); |
767 | CS_InsertEntry (S, X, IP++); |
768 | |
769 | /* clc */ |
770 | X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI); |
771 | CS_InsertEntry (S, X, IP++); |
772 | |
773 | } |
774 | |
775 | /* adc xxx */ |
776 | X = NewCodeEntry (L[2]->OPC, L[2]->AM, L[2]->Arg, 0, L[2]->LI); |
777 | CS_InsertEntry (S, X, IP++); |
778 | |
779 | /* sta ptr1 */ |
780 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[9]->LI); |
781 | CS_InsertEntry (S, X, IP++); |
782 | |
783 | if (ShortCode) { |
784 | /* txa */ |
785 | X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[4]->LI); |
786 | } else { |
787 | /* lda tmp1 */ |
788 | X = NewCodeEntry (OP65_LDA, AM65_ZP, "tmp1" , 0, L[4]->LI); |
789 | } |
790 | CS_InsertEntry (S, X, IP++); |
791 | |
792 | /* adc xxx */ |
793 | X = NewCodeEntry (L[5]->OPC, L[5]->AM, L[5]->Arg, 0, L[5]->LI); |
794 | CS_InsertEntry (S, X, IP++); |
795 | |
796 | /* sta ptr1+1 */ |
797 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1" , 0, L[9]->LI); |
798 | CS_InsertEntry (S, X, IP++); |
799 | |
800 | /* ldy zzz */ |
801 | X = NewCodeEntry (L[8]->OPC, L[8]->AM, L[8]->Arg, 0, L[8]->LI); |
802 | CS_InsertEntry (S, X, IP++); |
803 | |
804 | /* lda (ptr1),y */ |
805 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[9]->LI); |
806 | CS_InsertEntry (S, X, IP++); |
807 | |
808 | /* tax */ |
809 | X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[9]->LI); |
810 | CS_InsertEntry (S, X, IP++); |
811 | |
812 | /* dey */ |
813 | X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[9]->LI); |
814 | CS_InsertEntry (S, X, IP++); |
815 | |
816 | /* lda (ptr1),y */ |
817 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[9]->LI); |
818 | CS_InsertEntry (S, X, IP++); |
819 | |
820 | /* Remove the old code */ |
821 | CS_DelEntries (S, I, 10); |
822 | |
823 | /* Remember, we had changes */ |
824 | ++Changes; |
825 | |
826 | } |
827 | |
828 | /* Next entry */ |
829 | ++I; |
830 | |
831 | } |
832 | |
833 | /* Return the number of changes made */ |
834 | return Changes; |
835 | } |
836 | |
837 | |
838 | |
839 | unsigned OptPtrLoad11 (CodeSeg* S) |
840 | /* Search for the sequence: |
841 | ** |
842 | ** clc |
843 | ** adc xxx |
844 | ** bcc L |
845 | ** inx |
846 | ** L: ldy #$00 |
847 | ** jsr ldauidx |
848 | ** |
849 | ** and replace it by: |
850 | ** |
851 | ** ldy xxx |
852 | ** sta ptr1 |
853 | ** stx ptr1+1 |
854 | ** ldx #$00 |
855 | ** lda (ptr1),y |
856 | */ |
857 | { |
858 | unsigned Changes = 0; |
859 | |
860 | /* Walk over the entries */ |
861 | unsigned I = 0; |
862 | while (I < CS_GetEntryCount (S)) { |
863 | |
864 | CodeEntry* L[6]; |
865 | |
866 | /* Get next entry */ |
867 | L[0] = CS_GetEntry (S, I); |
868 | |
869 | /* Check for the sequence */ |
870 | if (L[0]->OPC == OP65_CLC && |
871 | CS_GetEntries (S, L+1, I+1, 5) && |
872 | L[1]->OPC == OP65_ADC && |
873 | (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP || L[1]->AM == AM65_IMM) && |
874 | (L[2]->OPC == OP65_BCC || L[2]->OPC == OP65_JCC) && |
875 | L[2]->JumpTo != 0 && |
876 | L[2]->JumpTo->Owner == L[4] && |
877 | L[3]->OPC == OP65_INX && |
878 | L[4]->OPC == OP65_LDY && |
879 | CE_IsKnownImm (L[4], 0) && |
880 | CE_IsCallTo (L[5], "ldauidx" ) && |
881 | !CS_RangeHasLabel (S, I+1, 3) && |
882 | !CE_HasLabel (L[5])) { |
883 | |
884 | CodeEntry* X; |
885 | |
886 | /* We will create all the new stuff behind the current one so |
887 | ** we keep the line references. |
888 | */ |
889 | X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[0]->LI); |
890 | CS_InsertEntry (S, X, I+6); |
891 | |
892 | /* sta ptr1 */ |
893 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[0]->LI); |
894 | CS_InsertEntry (S, X, I+7); |
895 | |
896 | /* stx ptr1+1 */ |
897 | X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1" , 0, L[0]->LI); |
898 | CS_InsertEntry (S, X, I+8); |
899 | |
900 | /* ldx #$00 */ |
901 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[0]->LI); |
902 | CS_InsertEntry (S, X, I+9); |
903 | |
904 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[0]->LI); |
905 | CS_InsertEntry (S, X, I+10); |
906 | |
907 | /* Remove the old code */ |
908 | CS_DelEntries (S, I, 6); |
909 | |
910 | /* Remember, we had changes */ |
911 | ++Changes; |
912 | |
913 | } |
914 | |
915 | /* Next entry */ |
916 | ++I; |
917 | |
918 | } |
919 | |
920 | /* Return the number of changes made */ |
921 | return Changes; |
922 | } |
923 | |
924 | |
925 | |
926 | unsigned OptPtrLoad12 (CodeSeg* S) |
927 | /* Search for the sequence: |
928 | ** |
929 | ** lda regbank+n |
930 | ** ldx regbank+n+1 |
931 | ** sta regsave |
932 | ** stx regsave+1 |
933 | ** clc |
934 | ** adc #$01 |
935 | ** bcc L0005 |
936 | ** inx |
937 | ** L: sta regbank+n |
938 | ** stx regbank+n+1 |
939 | ** lda regsave |
940 | ** ldx regsave+1 |
941 | ** ldy #$00 |
942 | ** jsr ldauidx |
943 | ** |
944 | ** and replace it by: |
945 | ** |
946 | ** ldy #$00 |
947 | ** ldx #$00 |
948 | ** lda (regbank+n),y |
949 | ** inc regbank+n |
950 | ** bne L1 |
951 | ** inc regbank+n+1 |
952 | ** L1: tay <- only if flags are used |
953 | ** |
954 | ** This function must execute before OptPtrLoad7! |
955 | ** |
956 | */ |
957 | { |
958 | unsigned Changes = 0; |
959 | |
960 | /* Walk over the entries */ |
961 | unsigned I = 0; |
962 | while (I < CS_GetEntryCount (S)) { |
963 | |
964 | CodeEntry* L[15]; |
965 | unsigned Len; |
966 | |
967 | /* Get next entry */ |
968 | L[0] = CS_GetEntry (S, I); |
969 | |
970 | /* Check for the sequence */ |
971 | if (L[0]->OPC == OP65_LDA && |
972 | L[0]->AM == AM65_ZP && |
973 | strncmp (L[0]->Arg, "regbank+" , 8) == 0 && |
974 | (Len = strlen (L[0]->Arg)) > 0 && |
975 | CS_GetEntries (S, L+1, I+1, 14) && |
976 | !CS_RangeHasLabel (S, I+1, 7) && |
977 | !CS_RangeHasLabel (S, I+9, 5) && |
978 | L[1]->OPC == OP65_LDX && |
979 | L[1]->AM == AM65_ZP && |
980 | strncmp (L[1]->Arg, L[0]->Arg, Len) == 0 && |
981 | strcmp (L[1]->Arg+Len, "+1" ) == 0 && |
982 | L[2]->OPC == OP65_STA && |
983 | L[2]->AM == AM65_ZP && |
984 | strcmp (L[2]->Arg, "regsave" ) == 0 && |
985 | L[3]->OPC == OP65_STX && |
986 | L[3]->AM == AM65_ZP && |
987 | strcmp (L[3]->Arg, "regsave+1" ) == 0 && |
988 | L[4]->OPC == OP65_CLC && |
989 | L[5]->OPC == OP65_ADC && |
990 | CE_IsKnownImm (L[5], 1) && |
991 | L[6]->OPC == OP65_BCC && |
992 | L[6]->JumpTo != 0 && |
993 | L[6]->JumpTo->Owner == L[8] && |
994 | L[7]->OPC == OP65_INX && |
995 | L[8]->OPC == OP65_STA && |
996 | L[8]->AM == AM65_ZP && |
997 | strcmp (L[8]->Arg, L[0]->Arg) == 0 && |
998 | L[9]->OPC == OP65_STX && |
999 | L[9]->AM == AM65_ZP && |
1000 | strcmp (L[9]->Arg, L[1]->Arg) == 0 && |
1001 | L[10]->OPC == OP65_LDA && |
1002 | L[10]->AM == AM65_ZP && |
1003 | strcmp (L[10]->Arg, "regsave" ) == 0 && |
1004 | L[11]->OPC == OP65_LDX && |
1005 | L[11]->AM == AM65_ZP && |
1006 | strcmp (L[11]->Arg, "regsave+1" ) == 0 && |
1007 | L[12]->OPC == OP65_LDY && |
1008 | CE_IsConstImm (L[12]) && |
1009 | CE_IsCallTo (L[13], "ldauidx" )) { |
1010 | |
1011 | CodeEntry* X; |
1012 | CodeLabel* Label; |
1013 | |
1014 | /* Check if the instruction following the sequence uses the flags |
1015 | ** set by the load. If so, insert a test of the value in the |
1016 | ** accumulator. |
1017 | */ |
1018 | if (CE_UseLoadFlags (L[14])) { |
1019 | X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI); |
1020 | CS_InsertEntry (S, X, I+14); |
1021 | } |
1022 | |
1023 | /* Attach a label to L[14]. This may be either the just inserted |
1024 | ** instruction, or the one following the sequence. |
1025 | */ |
1026 | Label = CS_GenLabel (S, L[14]); |
1027 | |
1028 | /* ldy #$xx */ |
1029 | X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI); |
1030 | CS_InsertEntry (S, X, I+14); |
1031 | |
1032 | /* ldx #$xx */ |
1033 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[13]->LI); |
1034 | CS_InsertEntry (S, X, I+15); |
1035 | |
1036 | /* lda (regbank+n),y */ |
1037 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI); |
1038 | CS_InsertEntry (S, X, I+16); |
1039 | |
1040 | /* inc regbank+n */ |
1041 | X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI); |
1042 | CS_InsertEntry (S, X, I+17); |
1043 | |
1044 | /* bne ... */ |
1045 | X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI); |
1046 | CS_InsertEntry (S, X, I+18); |
1047 | |
1048 | /* inc regbank+n+1 */ |
1049 | X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI); |
1050 | CS_InsertEntry (S, X, I+19); |
1051 | |
1052 | /* Delete the old code */ |
1053 | CS_DelEntries (S, I, 14); |
1054 | |
1055 | /* Remember, we had changes */ |
1056 | ++Changes; |
1057 | |
1058 | } |
1059 | |
1060 | /* Next entry */ |
1061 | ++I; |
1062 | |
1063 | } |
1064 | |
1065 | /* Return the number of changes made */ |
1066 | return Changes; |
1067 | } |
1068 | |
1069 | |
1070 | |
1071 | unsigned OptPtrLoad13 (CodeSeg* S) |
1072 | /* Search for the sequence: |
1073 | ** |
1074 | ** lda zp |
1075 | ** ldx zp+1 |
1076 | ** ldy xx |
1077 | ** jsr ldauidx |
1078 | ** |
1079 | ** and replace it by: |
1080 | ** |
1081 | ** ldy xx |
1082 | ** ldx #$00 |
1083 | ** lda (zp),y |
1084 | */ |
1085 | { |
1086 | unsigned Changes = 0; |
1087 | |
1088 | /* Walk over the entries */ |
1089 | unsigned I = 0; |
1090 | while (I < CS_GetEntryCount (S)) { |
1091 | |
1092 | CodeEntry* L[4]; |
1093 | unsigned Len; |
1094 | |
1095 | /* Get next entry */ |
1096 | L[0] = CS_GetEntry (S, I); |
1097 | |
1098 | /* Check for the sequence */ |
1099 | if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && |
1100 | CS_GetEntries (S, L+1, I+1, 3) && |
1101 | !CS_RangeHasLabel (S, I+1, 3) && |
1102 | L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && |
1103 | (Len = strlen (L[0]->Arg)) > 0 && |
1104 | strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && |
1105 | strcmp (L[1]->Arg + Len, "+1" ) == 0 && |
1106 | L[2]->OPC == OP65_LDY && |
1107 | CE_IsCallTo (L[3], "ldauidx" )) { |
1108 | |
1109 | CodeEntry* X; |
1110 | |
1111 | /* ldx #$00 */ |
1112 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[3]->LI); |
1113 | CS_InsertEntry (S, X, I+3); |
1114 | |
1115 | /* lda (zp),y */ |
1116 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); |
1117 | CS_InsertEntry (S, X, I+4); |
1118 | |
1119 | /* Remove the old code */ |
1120 | CS_DelEntry (S, I+5); |
1121 | CS_DelEntries (S, I, 2); |
1122 | |
1123 | /* Remember, we had changes */ |
1124 | ++Changes; |
1125 | |
1126 | } |
1127 | |
1128 | /* Next entry */ |
1129 | ++I; |
1130 | |
1131 | } |
1132 | |
1133 | /* Return the number of changes made */ |
1134 | return Changes; |
1135 | } |
1136 | |
1137 | |
1138 | |
1139 | unsigned OptPtrLoad14 (CodeSeg* S) |
1140 | /* Search for the sequence: |
1141 | ** |
1142 | ** lda zp |
1143 | ** ldx zp+1 |
1144 | ** (anything that doesn't change a/x) |
1145 | ** ldy xx |
1146 | ** jsr ldauidx |
1147 | ** |
1148 | ** and replace it by: |
1149 | ** |
1150 | ** lda zp |
1151 | ** ldx zp+1 |
1152 | ** (anything that doesn't change a/x) |
1153 | ** ldy xx |
1154 | ** ldx #$00 |
1155 | ** lda (zp),y |
1156 | */ |
1157 | { |
1158 | unsigned Changes = 0; |
1159 | unsigned I; |
1160 | |
1161 | /* Walk over the entries */ |
1162 | I = 0; |
1163 | while (I < CS_GetEntryCount (S)) { |
1164 | |
1165 | CodeEntry* L[5]; |
1166 | unsigned Len; |
1167 | |
1168 | /* Get next entry */ |
1169 | L[0] = CS_GetEntry (S, I); |
1170 | |
1171 | /* Check for the sequence */ |
1172 | if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && |
1173 | CS_GetEntries (S, L+1, I+1, 4) && |
1174 | !CS_RangeHasLabel (S, I+1, 4) && |
1175 | L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && |
1176 | (Len = strlen (L[0]->Arg)) > 0 && |
1177 | strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && |
1178 | strcmp (L[1]->Arg + Len, "+1" ) == 0 && |
1179 | (L[2]->Chg & REG_AX) == 0 && |
1180 | L[3]->OPC == OP65_LDY && |
1181 | CE_IsCallTo (L[4], "ldauidx" )) { |
1182 | |
1183 | CodeEntry* X; |
1184 | |
1185 | /* ldx #$00 */ |
1186 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[3]->LI); |
1187 | CS_InsertEntry (S, X, I+5); |
1188 | |
1189 | /* lda (zp),y */ |
1190 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); |
1191 | CS_InsertEntry (S, X, I+6); |
1192 | |
1193 | /* Remove the old code */ |
1194 | CS_DelEntry (S, I+4); |
1195 | |
1196 | /* Remember, we had changes */ |
1197 | ++Changes; |
1198 | |
1199 | } |
1200 | |
1201 | /* Next entry */ |
1202 | ++I; |
1203 | |
1204 | } |
1205 | |
1206 | /* Return the number of changes made */ |
1207 | return Changes; |
1208 | } |
1209 | |
1210 | |
1211 | |
1212 | unsigned OptPtrLoad15 (CodeSeg* S) |
1213 | /* Search for the sequence: |
1214 | ** |
1215 | ** lda zp |
1216 | ** ldx zp+1 |
1217 | ** jsr pushax <- optional |
1218 | ** ldy xx |
1219 | ** jsr ldaxidx |
1220 | ** |
1221 | ** and replace it by: |
1222 | ** |
1223 | ** lda zp <- only if |
1224 | ** ldx zp+1 <- call to |
1225 | ** jsr pushax <- pushax present |
1226 | ** ldy xx |
1227 | ** lda (zp),y |
1228 | ** tax |
1229 | ** dey |
1230 | ** lda (zp),y |
1231 | */ |
1232 | { |
1233 | unsigned Changes = 0; |
1234 | |
1235 | /* Walk over the entries */ |
1236 | unsigned I = 0; |
1237 | while (I < CS_GetEntryCount (S)) { |
1238 | |
1239 | CodeEntry* L[5]; |
1240 | unsigned Len; |
1241 | |
1242 | /* Check for the start of the sequence */ |
1243 | if (CS_GetEntries (S, L, I, 3) && |
1244 | L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP && |
1245 | L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP && |
1246 | !CS_RangeHasLabel (S, I+1, 2) && |
1247 | (Len = strlen (L[0]->Arg)) > 0 && |
1248 | strncmp (L[0]->Arg, L[1]->Arg, Len) == 0 && |
1249 | strcmp (L[1]->Arg + Len, "+1" ) == 0) { |
1250 | |
1251 | unsigned PushAX = CE_IsCallTo (L[2], "pushax" ); |
1252 | |
1253 | /* Check for the remainder of the sequence */ |
1254 | if (CS_GetEntries (S, L+3, I+3, 1 + PushAX) && |
1255 | !CS_RangeHasLabel (S, I+3, 1 + PushAX) && |
1256 | L[2+PushAX]->OPC == OP65_LDY && |
1257 | CE_IsCallTo (L[3+PushAX], "ldaxidx" )) { |
1258 | |
1259 | CodeEntry* X; |
1260 | |
1261 | /* lda (zp),y */ |
1262 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); |
1263 | CS_InsertEntry (S, X, I+PushAX+4); |
1264 | |
1265 | /* tax */ |
1266 | X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI); |
1267 | CS_InsertEntry (S, X, I+PushAX+5); |
1268 | |
1269 | /* dey */ |
1270 | X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI); |
1271 | CS_InsertEntry (S, X, I+PushAX+6); |
1272 | |
1273 | /* lda (zp),y */ |
1274 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI); |
1275 | CS_InsertEntry (S, X, I+PushAX+7); |
1276 | |
1277 | /* Remove the old code */ |
1278 | CS_DelEntry (S, I+PushAX+3); |
1279 | if (!PushAX) { |
1280 | CS_DelEntries (S, I, 2); |
1281 | } |
1282 | |
1283 | /* Remember, we had changes */ |
1284 | ++Changes; |
1285 | |
1286 | } |
1287 | } |
1288 | |
1289 | /* Next entry */ |
1290 | ++I; |
1291 | |
1292 | } |
1293 | |
1294 | /* Return the number of changes made */ |
1295 | return Changes; |
1296 | } |
1297 | |
1298 | |
1299 | |
1300 | unsigned OptPtrLoad16 (CodeSeg* S) |
1301 | /* Search for the sequence |
1302 | ** |
1303 | ** ldy ... |
1304 | ** jsr ldauidx |
1305 | ** |
1306 | ** and replace it by: |
1307 | ** |
1308 | ** stx ptr1+1 |
1309 | ** sta ptr1 |
1310 | ** ldy ... |
1311 | ** ldx #$00 |
1312 | ** lda (ptr1),y |
1313 | ** |
1314 | ** This step must be executed *after* OptPtrLoad1! |
1315 | */ |
1316 | { |
1317 | unsigned Changes = 0; |
1318 | |
1319 | /* Walk over the entries */ |
1320 | unsigned I = 0; |
1321 | while (I < CS_GetEntryCount (S)) { |
1322 | |
1323 | CodeEntry* L[2]; |
1324 | |
1325 | /* Get next entry */ |
1326 | L[0] = CS_GetEntry (S, I); |
1327 | |
1328 | /* Check for the sequence */ |
1329 | if (L[0]->OPC == OP65_LDY && |
1330 | CS_GetEntries (S, L+1, I+1, 1) && |
1331 | CE_IsCallTo (L[1], "ldauidx" ) && |
1332 | !CE_HasLabel (L[1])) { |
1333 | |
1334 | CodeEntry* X; |
1335 | |
1336 | /* stx ptr1+1 */ |
1337 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[1]->LI); |
1338 | CS_InsertEntry (S, X, I+2); |
1339 | |
1340 | /* sta ptr1 */ |
1341 | X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1" , 0, L[1]->LI); |
1342 | CS_InsertEntry (S, X, I+3); |
1343 | |
1344 | /* ldy ... */ |
1345 | X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI); |
1346 | CS_InsertEntry (S, X, I+4); |
1347 | |
1348 | /* ldx #$00 */ |
1349 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[1]->LI); |
1350 | CS_InsertEntry (S, X, I+5); |
1351 | |
1352 | /* lda (ptr1),y */ |
1353 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[1]->LI); |
1354 | CS_InsertEntry (S, X, I+6); |
1355 | |
1356 | /* Delete the old code */ |
1357 | CS_DelEntries (S, I, 2); |
1358 | |
1359 | /* Remember, we had changes */ |
1360 | ++Changes; |
1361 | |
1362 | } |
1363 | |
1364 | /* Next entry */ |
1365 | ++I; |
1366 | |
1367 | } |
1368 | |
1369 | /* Return the number of changes made */ |
1370 | return Changes; |
1371 | } |
1372 | |
1373 | |
1374 | |
1375 | unsigned OptPtrLoad17 (CodeSeg* S) |
1376 | /* Search for the sequence |
1377 | ** |
1378 | ** ldy ... |
1379 | ** jsr ldaxidx |
1380 | ** |
1381 | ** and replace it by: |
1382 | ** |
1383 | ** sta ptr1 |
1384 | ** stx ptr1+1 |
1385 | ** ldy ... |
1386 | ** lda (ptr1),y |
1387 | ** tax |
1388 | ** dey |
1389 | ** lda (ptr1),y |
1390 | ** |
1391 | ** This step must be executed *after* OptPtrLoad9! While code size increases |
1392 | ** by more than 200%, inlining will greatly improve visibility for the |
1393 | ** optimizer, so often part of the code gets improved later. So we will mark |
1394 | ** the step with less than 200% so it gets executed when -Oi is in effect. |
1395 | */ |
1396 | { |
1397 | unsigned Changes = 0; |
1398 | |
1399 | /* Walk over the entries */ |
1400 | unsigned I = 0; |
1401 | while (I < CS_GetEntryCount (S)) { |
1402 | |
1403 | CodeEntry* L[2]; |
1404 | |
1405 | /* Get next entry */ |
1406 | L[0] = CS_GetEntry (S, I); |
1407 | |
1408 | /* Check for the sequence */ |
1409 | if (L[0]->OPC == OP65_LDY && |
1410 | CS_GetEntries (S, L+1, I+1, 1) && |
1411 | CE_IsCallTo (L[1], "ldaxidx" ) && |
1412 | !CE_HasLabel (L[1])) { |
1413 | |
1414 | CodeEntry* X; |
1415 | |
1416 | /* Store the high byte */ |
1417 | X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1" , 0, L[0]->LI); |
1418 | CS_InsertEntry (S, X, I+2); |
1419 | |
1420 | /* Store the low byte */ |
1421 | X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1" , 0, L[0]->LI); |
1422 | CS_InsertEntry (S, X, I+3); |
1423 | |
1424 | /* ldy ... */ |
1425 | X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI); |
1426 | CS_InsertEntry (S, X, I+4); |
1427 | |
1428 | /* lda (ptr1),y */ |
1429 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[1]->LI); |
1430 | CS_InsertEntry (S, X, I+5); |
1431 | |
1432 | /* tax */ |
1433 | X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[1]->LI); |
1434 | CS_InsertEntry (S, X, I+6); |
1435 | |
1436 | /* dey */ |
1437 | X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI); |
1438 | CS_InsertEntry (S, X, I+7); |
1439 | |
1440 | /* lda (ptr1),y */ |
1441 | X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1" , 0, L[1]->LI); |
1442 | CS_InsertEntry (S, X, I+8); |
1443 | |
1444 | /* Delete original sequence */ |
1445 | CS_DelEntries (S, I, 2); |
1446 | |
1447 | /* Remember, we had changes */ |
1448 | ++Changes; |
1449 | |
1450 | } |
1451 | |
1452 | /* Next entry */ |
1453 | ++I; |
1454 | |
1455 | } |
1456 | |
1457 | /* Return the number of changes made */ |
1458 | return Changes; |
1459 | } |
1460 | |
1461 | |
1462 | |
1463 | unsigned OptPtrLoad18 (CodeSeg* S) |
1464 | /* Search for the sequence: |
1465 | ** |
1466 | ** ldx #$xx |
1467 | ** lda #$yy |
1468 | ** clc |
1469 | ** adc xxx |
1470 | ** bcc L |
1471 | ** inx |
1472 | ** L: ldy #$00 |
1473 | ** jsr ldauidx |
1474 | ** |
1475 | ** and replace it by: |
1476 | ** |
1477 | ** ldy xxx |
1478 | ** ldx #$00 |
1479 | ** lda $xxyy,y |
1480 | ** |
1481 | ** This is similar to OptPtrLoad3 but works on a constant address |
1482 | ** instead of a label. Also, the initial X and A loads are reversed. |
1483 | ** Must be run before OptPtrLoad7(). |
1484 | */ |
1485 | { |
1486 | unsigned Changes = 0; |
1487 | |
1488 | /* Walk over the entries */ |
1489 | unsigned I = 0; |
1490 | while (I < CS_GetEntryCount (S)) { |
1491 | |
1492 | CodeEntry* L[8]; |
1493 | |
1494 | /* Get next entry */ |
1495 | L[0] = CS_GetEntry (S, I); |
1496 | |
1497 | /* Check for the sequence */ |
1498 | if (L[0]->OPC == OP65_LDX && |
1499 | L[0]->AM == AM65_IMM && |
1500 | CS_GetEntries (S, L+1, I+1, 7) && |
1501 | L[1]->OPC == OP65_LDA && |
1502 | L[1]->AM == AM65_IMM && |
1503 | L[2]->OPC == OP65_CLC && |
1504 | L[3]->OPC == OP65_ADC && |
1505 | (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP) && |
1506 | (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) && |
1507 | L[4]->JumpTo != 0 && |
1508 | L[4]->JumpTo->Owner == L[6] && |
1509 | L[5]->OPC == OP65_INX && |
1510 | L[6]->OPC == OP65_LDY && |
1511 | CE_IsKnownImm (L[6], 0) && |
1512 | CE_IsCallTo (L[7], "ldauidx" ) && |
1513 | !CS_RangeHasLabel (S, I+1, 5) && |
1514 | !CE_HasLabel (L[7]) && |
1515 | L[0]->Arg[0] == '$' && |
1516 | L[1]->Arg[0] == '$' && |
1517 | strlen (L[0]->Arg) == 3 && |
1518 | strlen (L[1]->Arg) == 3 ) { |
1519 | |
1520 | CodeEntry* X; |
1521 | char* Label; |
1522 | |
1523 | /* We will create all the new stuff behind the current one so |
1524 | ** we keep the line references. |
1525 | */ |
1526 | X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI); |
1527 | CS_InsertEntry (S, X, I+8); |
1528 | |
1529 | X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00" , 0, L[0]->LI); |
1530 | CS_InsertEntry (S, X, I+9); |
1531 | |
1532 | Label = xmalloc(6); |
1533 | sprintf(Label, "$%s%s" , L[0]->Arg+1, L[1]->Arg+1); |
1534 | X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI); |
1535 | CS_InsertEntry (S, X, I+10); |
1536 | xfree (Label); |
1537 | |
1538 | /* Remove the old code */ |
1539 | CS_DelEntries (S, I, 8); |
1540 | |
1541 | /* Remember, we had changes */ |
1542 | ++Changes; |
1543 | |
1544 | } |
1545 | |
1546 | /* Next entry */ |
1547 | ++I; |
1548 | |
1549 | } |
1550 | |
1551 | /* Return the number of changes made */ |
1552 | return Changes; |
1553 | } |
1554 | |
1555 | |
1556 | |
1557 | unsigned OptPtrLoad19 (CodeSeg* S) |
1558 | /* Search for the sequence: |
1559 | ** |
1560 | ** ldx #0 |
1561 | ** and #mask (any value < 0x80) |
1562 | ** jsr aslax1/shlax1 |
1563 | ** clc |
1564 | ** adc #<(label+0) |
1565 | ** tay |
1566 | ** txa |
1567 | ** adc #>(label+0) |
1568 | ** tax |
1569 | ** tya |
1570 | ** ldy #$01 |
1571 | ** jsr ldaxidx |
1572 | ** |
1573 | ** and replace it by: |
1574 | ** |
1575 | ** and #mask (remove if == 0x7F) |
1576 | ** asl |
1577 | ** tay |
1578 | ** lda label,y |
1579 | ** ldx label+1,y |
1580 | */ |
1581 | { |
1582 | unsigned Changes = 0; |
1583 | unsigned I; |
1584 | |
1585 | /* Walk over the entries */ |
1586 | I = 0; |
1587 | while (I < CS_GetEntryCount (S)) { |
1588 | |
1589 | CodeEntry* L[12]; |
1590 | |
1591 | /* Get next entry */ |
1592 | L[0] = CS_GetEntry (S, I); |
1593 | |
1594 | /* Check for the sequence */ |
1595 | if (L[0]->OPC == OP65_LDX && |
1596 | CE_IsKnownImm(L[0], 0) && |
1597 | CS_GetEntries (S, L+1, I+1, 11) && |
1598 | L[1]->OPC == OP65_AND && |
1599 | L[1]->AM == AM65_IMM && |
1600 | CE_HasNumArg (L[1]) && L[1]->Num <= 0x7F && |
1601 | L[2]->OPC == OP65_JSR && |
1602 | L[3]->OPC == OP65_CLC && |
1603 | L[4]->OPC == OP65_ADC && |
1604 | L[5]->OPC == OP65_TAY && |
1605 | L[6]->OPC == OP65_TXA && |
1606 | L[7]->OPC == OP65_ADC && |
1607 | L[8]->OPC == OP65_TAX && |
1608 | L[9]->OPC == OP65_TYA && |
1609 | L[10]->OPC == OP65_LDY && |
1610 | CE_IsKnownImm(L[10], 1) && |
1611 | L[4]->Arg[0] == '<' && |
1612 | L[7]->Arg[0] == '>' && |
1613 | strlen(L[4]->Arg) > 3 && |
1614 | strlen(L[7]->Arg) > 3 && |
1615 | strcmp(L[4]->Arg+1, L[7]->Arg+1) == 0 && |
1616 | (strcmp (L[2]->Arg, "aslax1" ) == 0 || |
1617 | strcmp (L[2]->Arg, "shlax1" ) == 0) && |
1618 | CE_IsCallTo (L[11], "ldaxidx" ) && |
1619 | !CS_RangeHasLabel (S, I+1, 11)) { |
1620 | |
1621 | CodeEntry* X; |
1622 | char* Label; |
1623 | int Len = strlen(L[4]->Arg); |
1624 | |
1625 | /* Track the insertion point */ |
1626 | unsigned IP = I + 12; |
1627 | |
1628 | /* asl a */ |
1629 | X = NewCodeEntry (OP65_ASL, AM65_ACC, "a" , 0, L[2]->LI); |
1630 | CS_InsertEntry (S, X, IP++); |
1631 | |
1632 | /* tay */ |
1633 | X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[2]->LI); |
1634 | CS_InsertEntry (S, X, IP++); |
1635 | |
1636 | /* lda label,y */ |
1637 | /* allocate Label memory */ |
1638 | Label = memcpy (xmalloc (Len), L[4]->Arg+2, Len-3); |
1639 | Label[Len-3] = '\0'; |
1640 | X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[10]->LI); |
1641 | CS_InsertEntry (S, X, IP++); |
1642 | |
1643 | /* ldx label+1,y */ |
1644 | strcpy(&Label[Len-3], "+1" ); |
1645 | X = NewCodeEntry (OP65_LDX, AM65_ABSY, Label, 0, L[10]->LI); |
1646 | CS_InsertEntry (S, X, IP++); |
1647 | /* free Label memory */ |
1648 | xfree (Label); |
1649 | |
1650 | /* Remove the old code */ |
1651 | /* Remove the AND only if it's == 0x7F, since ASL erases high bit */ |
1652 | if (L[1]->Num == 0x7F) { |
1653 | CS_DelEntries (S, I+1, 11); |
1654 | } else { |
1655 | CS_DelEntries (S, I+2, 10); |
1656 | } |
1657 | |
1658 | /* Remove the ldx #0 */ |
1659 | CS_DelEntry(S, I); |
1660 | |
1661 | /* Remember, we had changes */ |
1662 | ++Changes; |
1663 | |
1664 | } |
1665 | |
1666 | /* Next entry */ |
1667 | ++I; |
1668 | |
1669 | } |
1670 | |
1671 | /* Return the number of changes made */ |
1672 | return Changes; |
1673 | } |
1674 | |