1 /*****************************************************************************/
5 /* Optimizer subroutines */
9 /* (C) 2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
53 /*****************************************************************************/
55 /*****************************************************************************/
59 /* Defines for the conditions in a compare */
74 /* Table with the compare suffixes */
75 static const char CmpSuffixTab [][4] = {
76 "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
79 /* Table used to invert a condition, indexed by condition */
80 static const unsigned char CmpInvertTab [] = {
82 CMP_LE, CMP_LT, CMP_GE, CMP_GT,
83 CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
86 /* Table to show which compares are signed (use the N flag) */
87 static const char CmpSignedTab [] = {
88 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
93 /*****************************************************************************/
94 /* Helper functions */
95 /*****************************************************************************/
99 static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
100 /* Search for a compare condition by the given code using the given length */
105 for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
106 if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
118 static cmp_t FindBoolCmpCond (const char* Name)
119 /* Map a condition suffix to a code. Return the code or CMP_INV on failure */
121 /* Check for the correct subroutine name */
122 if (strncmp (Name, "bool", 4) == 0) {
123 /* Name is ok, search for the code in the table */
124 return FindCmpCond (Name+4, strlen(Name)-4);
133 static cmp_t FindTosCmpCond (const char* Name)
134 /* Check if this is a call to one of the TOS compare functions (tosgtax).
135 * Return the condition code or CMP_INV on failure.
138 unsigned Len = strlen (Name);
140 /* Check for the correct subroutine name */
141 if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
142 /* Name is ok, search for the code in the table */
143 return FindCmpCond (Name+3, Len-3-2);
152 static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
153 /* Helper function for the replacement of routines that return a boolean
154 * followed by a conditional jump. Instead of the boolean value, the condition
155 * codes are evaluated directly.
156 * I is the index of the conditional branch, the sequence is already checked
164 CodeEntry* E = GetCodeEntry (S, I);
166 /* Replace the conditional branch */
170 ReplaceOPC (E, OPC_JEQ);
174 ReplaceOPC (E, OPC_JNE);
183 if ((N = GetNextCodeEntry (S, I)) == 0) {
185 Internal ("Invalid program flow");
187 L = GenCodeLabel (S, N);
188 N = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L, E->LI);
189 InsertCodeEntry (S, N, I);
190 ReplaceOPC (E, OPC_JPL);
194 ReplaceOPC (E, OPC_JPL);
198 ReplaceOPC (E, OPC_JMI);
206 ReplaceOPC (E, OPC_JMI);
208 N = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L, E->LI);
209 InsertCodeEntry (S, N, I+1);
218 if ((N = GetNextCodeEntry (S, I)) == 0) {
220 Internal ("Invalid program flow");
222 L = GenCodeLabel (S, N);
223 N = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L, E->LI);
224 InsertCodeEntry (S, N, I);
225 ReplaceOPC (E, OPC_JCS);
229 ReplaceOPC (E, OPC_JCS);
233 ReplaceOPC (E, OPC_JCC);
241 ReplaceOPC (E, OPC_JCC);
243 N = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L, E->LI);
244 InsertCodeEntry (S, N, I+1);
248 Internal ("Unknown jump condition: %d", Cond);
256 static int IsUnsignedCmp (int Code)
257 /* Check if this is an unsigned compare */
260 return CmpSignedTab [Code] == 0;
265 static int IsBitOp (const CodeEntry* E)
266 /* Check if E is one of the bit operations (and, or, eor) */
268 return (E->OPC == OPC_AND || E->OPC == OPC_ORA || E->OPC == OPC_EOR);
273 static int IsCmpToZero (const CodeEntry* E)
274 /* Check if the given instrcuction is a compare to zero instruction */
276 return (E->OPC == OPC_CMP &&
278 (E->Flags & CEF_NUMARG) != 0 &&
284 static int IsSpLoad (const CodeEntry* E)
285 /* Return true if this is the load of A from the stack */
287 return E->OPC == OPC_LDA && E->AM == AM_ZP_INDY && strcmp (E->Arg, "sp") == 0;
292 static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
293 CodeEntry** L, unsigned Count)
294 /* Check if a 16 bit load of a local variable follows:
302 * If so, read Count entries following the first ldy into L and return true
303 * if this is possible. Otherwise return false.
306 /* Be sure we read enough entries for the check */
309 /* Read the first entry */
310 L[0] = GetCodeEntry (S, Index);
312 /* Check for the sequence */
313 return (L[0]->OPC == OPC_LDY &&
314 L[0]->AM == AM_IMM &&
315 (L[0]->Flags & CEF_NUMARG) != 0 &&
316 GetCodeEntries (S, L+1, Index+1, Count-1) &&
318 !CodeEntryHasLabel (L[1]) &&
319 L[2]->OPC == OPC_TAX &&
320 !CodeEntryHasLabel (L[2]) &&
321 L[3]->OPC == OPC_DEY &&
322 !CodeEntryHasLabel (L[3]) &&
324 !CodeEntryHasLabel (L[4]));
329 static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
330 /* Check if the instructions at L are an immidiate compare of a/x:
335 return (L[0]->OPC == OPC_CPX &&
336 L[0]->AM == AM_IMM &&
337 (L[0]->Flags & CEF_NUMARG) != 0 &&
338 !CodeEntryHasLabel (L[0]) &&
339 (L[1]->OPC == OPC_JNE || L[1]->OPC == OPC_BNE) &&
341 !CodeEntryHasLabel (L[1]) &&
342 L[2]->OPC == OPC_CMP &&
343 L[2]->AM == AM_IMM &&
344 (L[2]->Flags & CEF_NUMARG) != 0 &&
345 (L[3]->Info & OF_ZBRA) != 0 &&
347 (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
352 /*****************************************************************************/
353 /* Remove calls to the bool transformer subroutines */
354 /*****************************************************************************/
358 static unsigned OptBoolTransforms (CodeSeg* S)
359 /* Try to remove the call to boolean transformer routines where the call is
363 unsigned Changes = 0;
365 /* Walk over the entries */
367 while (I < GetCodeEntryCount (S)) {
373 CodeEntry* E = GetCodeEntry (S, I);
375 /* Check for a boolean transformer */
376 if (E->OPC == OPC_JSR &&
377 (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
378 (N = GetNextCodeEntry (S, I)) != 0 &&
379 (N->Info & OF_ZBRA) != 0) {
381 /* Make the boolean transformer unnecessary by changing the
382 * the conditional jump to evaluate the condition flags that
383 * are set after the compare directly. Note: jeq jumps if
384 * the condition is not met, jne jumps if the condition is met.
385 * Invert the code if we jump on condition not met.
387 if (GetBranchCond (N->OPC) == BC_EQ) {
388 /* Jumps if condition false, invert condition */
389 Cond = CmpInvertTab [Cond];
392 /* Check if we can replace the code by something better */
393 ReplaceCmp (S, I+1, Cond);
395 /* Remove the call to the bool transformer */
398 /* Remember, we had changes */
408 /* Return the number of changes made */
414 /*****************************************************************************/
415 /* Optimize subtractions */
416 /*****************************************************************************/
420 static unsigned OptSub1 (CodeSeg* S)
421 /* Search for the sequence
428 * and remove the handling of the high byte if X is not used later.
431 unsigned Changes = 0;
433 /* Walk over the entries */
435 while (I < GetCodeEntryCount (S)) {
440 CodeEntry* E = GetCodeEntry (S, I);
442 /* Check for the sequence */
443 if (E->OPC == OPC_SBC &&
444 GetCodeEntries (S, L, I+1, 3) &&
445 (L[0]->OPC == OPC_BCS || L[0]->OPC == OPC_JCS) &&
447 !CodeEntryHasLabel (L[0]) &&
448 L[1]->OPC == OPC_DEX &&
449 !CodeEntryHasLabel (L[1]) &&
450 L[0]->JumpTo->Owner == L[2] &&
451 !RegXUsed (S, I+3)) {
453 /* Remove the bcs/dex */
454 DelCodeEntries (S, I+1, 2);
456 /* Remember, we had changes */
466 /* Return the number of changes made */
472 static unsigned OptSub2 (CodeSeg* S)
473 /* Search for the sequence
490 unsigned Changes = 0;
492 /* Walk over the entries */
494 while (I < GetCodeEntryCount (S)) {
499 CodeEntry* E = GetCodeEntry (S, I);
501 /* Check for the sequence */
502 if (E->OPC == OPC_LDA &&
503 GetCodeEntries (S, L, I+1, 5) &&
504 L[0]->OPC == OPC_SEC &&
505 !CodeEntryHasLabel (L[0]) &&
506 L[1]->OPC == OPC_STA &&
507 strcmp (L[1]->Arg, "tmp1") == 0 &&
508 !CodeEntryHasLabel (L[1]) &&
509 L[2]->OPC == OPC_LDA &&
510 !CodeEntryHasLabel (L[2]) &&
511 L[3]->OPC == OPC_SBC &&
512 strcmp (L[3]->Arg, "tmp1") == 0 &&
513 !CodeEntryHasLabel (L[3]) &&
514 L[4]->OPC == OPC_STA &&
515 strcmp (L[4]->Arg, L[2]->Arg) == 0 &&
516 !CodeEntryHasLabel (L[4])) {
518 /* Remove the store to tmp1 */
519 DelCodeEntry (S, I+2);
521 /* Remove the subtraction */
522 DelCodeEntry (S, I+3);
524 /* Move the lda to the position of the subtraction and change the
527 MoveCodeEntry (S, I, I+3);
528 ReplaceOPC (E, OPC_SBC);
530 /* If the sequence head had a label, move this label back to the
533 if (CodeEntryHasLabel (E)) {
534 MoveCodeLabels (S, E, L[0]);
537 /* Remember, we had changes */
547 /* Return the number of changes made */
553 /*****************************************************************************/
554 /* Optimize additions */
555 /*****************************************************************************/
559 static unsigned OptAdd1 (CodeSeg* S)
560 /* Search for the sequence
567 * and remove the handling of the high byte if X is not used later.
570 unsigned Changes = 0;
572 /* Walk over the entries */
574 while (I < GetCodeEntryCount (S)) {
579 CodeEntry* E = GetCodeEntry (S, I);
581 /* Check for the sequence */
582 if (E->OPC == OPC_ADC &&
583 GetCodeEntries (S, L, I+1, 3) &&
584 (L[0]->OPC == OPC_BCC || L[0]->OPC == OPC_JCC) &&
586 !CodeEntryHasLabel (L[0]) &&
587 L[1]->OPC == OPC_INX &&
588 !CodeEntryHasLabel (L[1]) &&
589 L[0]->JumpTo->Owner == L[2] &&
590 !RegXUsed (S, I+3)) {
592 /* Remove the bcs/dex */
593 DelCodeEntries (S, I+1, 2);
595 /* Remember, we had changes */
605 /* Return the number of changes made */
611 /*****************************************************************************/
612 /* Optimizations for compares */
613 /*****************************************************************************/
617 static unsigned OptCmp1 (CodeSeg* S)
618 /* Search for the sequence
630 unsigned Changes = 0;
632 /* Walk over the entries */
634 while (I < GetCodeEntryCount (S)) {
639 CodeEntry* E = GetCodeEntry (S, I);
641 /* Check for the sequence */
642 if (E->OPC == OPC_STX &&
643 GetCodeEntries (S, L, I+1, 2) &&
644 L[0]->OPC == OPC_STX &&
645 strcmp (L[0]->Arg, "tmp1") == 0 &&
646 !CodeEntryHasLabel (L[0]) &&
647 L[1]->OPC == OPC_ORA &&
648 strcmp (L[1]->Arg, "tmp1") == 0 &&
649 !CodeEntryHasLabel (L[1])) {
651 /* Remove the remaining instructions */
652 DelCodeEntries (S, I+1, 2);
654 /* Insert the ora instead */
655 InsertCodeEntry (S, NewCodeEntry (OPC_ORA, E->AM, E->Arg, 0, E->LI), I+1);
657 /* Remember, we had changes */
667 /* Return the number of changes made */
673 static unsigned OptCmp2 (CodeSeg* S)
676 * lda/and/ora/eor ...
680 * and remove the cmp.
683 unsigned Changes = 0;
685 /* Walk over the entries */
687 while (I < GetCodeEntryCount (S)) {
692 CodeEntry* E = GetCodeEntry (S, I);
694 /* Check for the sequence */
695 if ((E->OPC == OPC_LDA || IsBitOp (E)) &&
696 GetCodeEntries (S, L, I+1, 2) &&
697 IsCmpToZero (L[0]) &&
698 !CodeEntryHasLabel (L[0]) &&
699 (L[1]->Info & OF_FBRA) != 0 &&
700 !CodeEntryHasLabel (L[1])) {
702 /* Remove the compare */
703 DelCodeEntry (S, I+1);
705 /* Remember, we had changes */
715 /* Return the number of changes made */
721 static unsigned OptCmp3 (CodeSeg* S)
731 * If a is zero, we may remove the compare. If a and b are both zero, we may
732 * replace it by the sequence
738 * L1 may be either the label at the branch instruction, or the target label
739 * of this instruction.
742 unsigned Changes = 0;
744 /* Walk over the entries */
746 while (I < GetCodeEntryCount (S)) {
751 CodeEntry* E = GetCodeEntry (S, I);
753 /* Check for the sequence */
754 if (E->OPC == OPC_LDA &&
755 GetCodeEntries (S, L, I+1, 5) &&
756 L[0]->OPC == OPC_LDX &&
757 !CodeEntryHasLabel (L[0]) &&
758 IsImmCmp16 (S, L+1)) {
760 if (L[1]->Num == 0 && L[3]->Num == 0) {
761 /* The value is zero, we may use the simple code version. */
762 ReplaceOPC (L[0], OPC_ORA);
763 DelCodeEntries (S, I+2, 3);
765 /* Move the lda instruction after the first branch. This will
766 * improve speed, since the load is delayed after the first
769 MoveCodeEntry (S, I, I+4);
771 /* We will replace the ldx/cpx by lda/cmp */
772 ReplaceOPC (L[0], OPC_LDA);
773 ReplaceOPC (L[1], OPC_CMP);
775 /* Beware: If the first LDA instruction had a label, we have
776 * to move this label to the top of the sequence again.
778 if (CodeEntryHasLabel (E)) {
779 MoveCodeLabels (S, E, L[0]);
792 /* Return the number of changes made */
798 static unsigned OptCmp4 (CodeSeg* S)
799 /* Optimize compares of local variables:
812 unsigned Changes = 0;
814 /* Walk over the entries */
816 while (I < GetCodeEntryCount (S)) {
820 /* Check for the sequence */
821 if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
823 if (L[5]->Num == 0 && L[7]->Num == 0) {
825 /* The value is zero, we may use the simple code version:
832 ReplaceOPC (L[4], OPC_ORA);
833 DelCodeEntries (S, I+5, 3); /* cpx/bne/cmp */
834 DelCodeEntry (S, I+2); /* tax */
838 /* Change the code to just use the A register. Move the load
839 * of the low byte after the first branch if possible:
850 DelCodeEntry (S, I+2); /* tax */
851 ReplaceOPC (L[5], OPC_CMP); /* cpx -> cmp */
852 MoveCodeEntry (S, I+4, I+2); /* cmp */
853 MoveCodeEntry (S, I+5, I+3); /* bne */
865 /* Return the number of changes made */
871 static unsigned OptCmp5 (CodeSeg* S)
872 /* Search for calls to compare subroutines followed by a conditional branch
873 * and replace them by cheaper versions, since the branch means that the
874 * boolean value returned by these routines is not needed (we may also check
875 * that explicitly, but for the current code generator it is always true).
878 unsigned Changes = 0;
880 /* Walk over the entries */
882 while (I < GetCodeEntryCount (S)) {
888 CodeEntry* E = GetCodeEntry (S, I);
890 /* Check for the sequence */
891 if (E->OPC == OPC_JSR &&
892 (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
893 (N = GetNextCodeEntry (S, I)) != 0 &&
894 (N->Info & OF_ZBRA) != 0 &&
895 !CodeEntryHasLabel (N)) {
897 /* The tos... functions will return a boolean value in a/x and
898 * the Z flag says if this value is zero or not. We will call
899 * a cheaper subroutine instead, one that does not return a
900 * boolean value but only valid flags. Note: jeq jumps if
901 * the condition is not met, jne jumps if the condition is met.
902 * Invert the code if we jump on condition not met.
904 if (GetBranchCond (N->OPC) == BC_EQ) {
905 /* Jumps if condition false, invert condition */
906 Cond = CmpInvertTab [Cond];
909 /* Replace the subroutine call. */
910 E = NewCodeEntry (OPC_JSR, AM_ABS, "tosicmp", 0, E->LI);
911 InsertCodeEntry (S, E, I+1);
914 /* Replace the conditional branch */
915 ReplaceCmp (S, I+1, Cond);
917 /* Remember, we had changes */
927 /* Return the number of changes made */
933 /*****************************************************************************/
934 /* nega optimizations */
935 /*****************************************************************************/
939 static unsigned OptNegA1 (CodeSeg* S)
946 * Remove the ldx if the lda does not use it.
949 unsigned Changes = 0;
951 /* Walk over the entries */
953 while (I < GetCodeEntryCount (S)) {
958 CodeEntry* E = GetCodeEntry (S, I);
960 /* Check for a ldx */
961 if (E->OPC == OPC_LDX &&
963 (E->Flags & CEF_NUMARG) != 0 &&
965 GetCodeEntries (S, L, I+1, 2) &&
966 L[0]->OPC == OPC_LDA &&
967 (L[0]->Use & REG_X) == 0 &&
968 L[1]->OPC == OPC_JSR &&
969 strcmp (L[1]->Arg, "bnega") == 0) {
971 /* Remove the ldx instruction */
974 /* Remember, we had changes */
984 /* Return the number of changes made */
990 static unsigned OptNegA2 (CodeSeg* S)
997 * Adjust the conditional branch and remove the call to the subroutine.
1000 unsigned Changes = 0;
1002 /* Walk over the entries */
1004 while (I < GetCodeEntryCount (S)) {
1008 /* Get next entry */
1009 CodeEntry* E = GetCodeEntry (S, I);
1011 /* Check for the sequence */
1012 if (E->OPC == OPC_LDA &&
1013 GetCodeEntries (S, L, I+1, 2) &&
1014 L[0]->OPC == OPC_JSR &&
1015 strcmp (L[0]->Arg, "bnega") == 0 &&
1016 !CodeEntryHasLabel (L[0]) &&
1017 (L[1]->Info & OF_ZBRA) != 0) {
1019 /* Invert the branch */
1020 ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
1022 /* Delete the subroutine call */
1023 DelCodeEntry (S, I+1);
1025 /* Remember, we had changes */
1035 /* Return the number of changes made */
1041 /*****************************************************************************/
1042 /* negax optimizations */
1043 /*****************************************************************************/
1047 static unsigned OptNegAX1 (CodeSeg* S)
1048 /* Search for the sequence:
1065 unsigned Changes = 0;
1067 /* Walk over the entries */
1069 while (I < GetCodeEntryCount (S)) {
1073 /* Get next entry */
1074 CodeEntry* E = GetCodeEntry (S, I);
1076 /* Check for the sequence */
1077 if (E->OPC == OPC_LDA &&
1078 E->AM == AM_ZP_INDY &&
1079 GetCodeEntries (S, L, I+1, 5) &&
1080 L[0]->OPC == OPC_TAX &&
1081 L[1]->OPC == OPC_DEY &&
1082 L[2]->OPC == OPC_LDA &&
1083 L[2]->AM == AM_ZP_INDY &&
1084 strcmp (L[2]->Arg, E->Arg) == 0 &&
1085 !CodeEntryHasLabel (L[2]) &&
1086 L[3]->OPC == OPC_JSR &&
1087 strcmp (L[3]->Arg, "bnegax") == 0 &&
1088 !CodeEntryHasLabel (L[3]) &&
1089 (L[4]->Info & OF_ZBRA) != 0) {
1092 ReplaceOPC (L[2], OPC_ORA);
1094 /* Invert the branch */
1095 ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
1097 /* Delete the entries no longer needed. Beware: Deleting entries
1098 * will change the indices.
1100 DelCodeEntry (S, I+4); /* jsr bnegax */
1101 DelCodeEntry (S, I+1); /* tax */
1103 /* Remember, we had changes */
1113 /* Return the number of changes made */
1119 static unsigned OptNegAX2 (CodeSeg* S)
1120 /* Search for the sequence:
1134 unsigned Changes = 0;
1136 /* Walk over the entries */
1138 while (I < GetCodeEntryCount (S)) {
1142 /* Get next entry */
1143 CodeEntry* E = GetCodeEntry (S, I);
1145 /* Check for the sequence */
1146 if (E->OPC == OPC_LDA &&
1147 GetCodeEntries (S, L, I+1, 3) &&
1148 L[0]->OPC == OPC_LDX &&
1149 !CodeEntryHasLabel (L[0]) &&
1150 L[1]->OPC == OPC_JSR &&
1151 strcmp (L[1]->Arg, "bnegax") == 0 &&
1152 !CodeEntryHasLabel (L[1]) &&
1153 (L[2]->Info & OF_ZBRA) != 0) {
1156 ReplaceOPC (L[0], OPC_ORA);
1158 /* Invert the branch */
1159 ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
1161 /* Delete the subroutine call */
1162 DelCodeEntry (S, I+2);
1164 /* Remember, we had changes */
1174 /* Return the number of changes made */
1180 static unsigned OptNegAX3 (CodeSeg* S)
1181 /* Search for the sequence:
1187 * and replace it by:
1194 unsigned Changes = 0;
1196 /* Walk over the entries */
1198 while (I < GetCodeEntryCount (S)) {
1202 /* Get next entry */
1203 CodeEntry* E = GetCodeEntry (S, I);
1205 /* Check for the sequence */
1206 if (E->OPC == OPC_JSR &&
1208 GetCodeEntries (S, L, I+1, 2) &&
1209 L[0]->OPC == OPC_JSR &&
1210 strncmp (L[0]->Arg,"bnega",5) == 0 &&
1211 !CodeEntryHasLabel (L[0]) &&
1212 (L[1]->Info & OF_ZBRA) != 0) {
1216 /* Check if we're calling bnega or bnegax */
1217 int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
1219 /* Insert apropriate test code */
1222 X = NewCodeEntry (OPC_TAX, AM_IMP, 0, 0, L[0]->LI);
1223 InsertCodeEntry (S, X, I+2);
1226 X = NewCodeEntry (OPC_STX, AM_ZP, "tmp1", 0, L[0]->LI);
1227 InsertCodeEntry (S, X, I+2);
1228 X = NewCodeEntry (OPC_ORA, AM_ZP, "tmp1", 0, L[0]->LI);
1229 InsertCodeEntry (S, X, I+3);
1232 /* Delete the subroutine call */
1233 DelCodeEntry (S, I+1);
1235 /* Invert the branch */
1236 ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
1238 /* Remember, we had changes */
1248 /* Return the number of changes made */
1254 /*****************************************************************************/
1256 /*****************************************************************************/
1260 /* Table with all the optimization functions */
1261 typedef struct OptFunc OptFunc;
1263 unsigned (*Func) (CodeSeg*);/* Optimizer function */
1264 const char* Name; /* Name of optimizer step */
1265 char Disabled; /* True if pass disabled */
1270 /* Table with optimizer steps - are called in this order */
1271 static OptFunc OptFuncs [] = {
1272 /* Optimize subtractions */
1273 { OptSub1, "OptSub1", 0 },
1274 { OptSub2, "OptSub2", 0 },
1275 /* Optimize additions */
1276 { OptAdd1, "OptAdd1", 0 },
1277 /* Optimize jump cascades */
1278 { OptJumpCascades, "OptJumpCascades", 0 },
1279 /* Remove dead jumps */
1280 { OptDeadJumps, "OptDeadJumps", 0 },
1281 /* Change jsr/rts to jmp */
1282 { OptRTS, "OptRTS", 0 },
1283 /* Remove dead code */
1284 { OptDeadCode, "OptDeadCode", 0 },
1285 /* Optimize jump targets */
1286 { OptJumpTarget, "OptJumpTarget", 0 },
1287 /* Optimize conditional branches */
1288 { OptCondBranches, "OptCondBranches", 0 },
1289 /* Replace jumps to RTS by RTS */
1290 { OptRTSJumps, "OptRTSJumps", 0 },
1291 /* Remove calls to the bool transformer subroutines */
1292 { OptBoolTransforms, "OptBoolTransforms", 0 },
1293 /* Optimize calls to nega */
1294 { OptNegA1, "OptNegA1", 0 },
1295 { OptNegA2, "OptNegA2", 0 },
1296 /* Optimize calls to negax */
1297 { OptNegAX1, "OptNegAX1", 0 },
1298 { OptNegAX2, "OptNegAX2", 0 },
1299 { OptNegAX3, "OptNegAX3", 0 },
1300 /* Optimize compares */
1301 { OptCmp1, "OptCmp1", 0 },
1302 { OptCmp2, "OptCmp2", 0 },
1303 { OptCmp3, "OptCmp3", 0 },
1304 { OptCmp4, "OptCmp4", 0 },
1305 { OptCmp5, "OptCmp5", 0 },
1306 /* Remove unused loads */
1307 { OptUnusedLoads, "OptUnusedLoads", 0 },
1308 /* Optimize branch distance */
1309 { OptBranchDist, "OptBranchDist", 0 },
1314 static OptFunc* FindOptStep (const char* Name)
1315 /* Find an optimizer step by name in the table and return a pointer. Print an
1316 * error and call AbEnd if not found.
1321 /* Run all optimization steps */
1322 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1323 if (strcmp (OptFuncs[I].Name, Name) == 0) {
1330 AbEnd ("Optimization step `%s' not found", Name);
1336 void DisableOpt (const char* Name)
1337 /* Disable the optimization with the given name */
1339 if (strcmp (Name, "any") == 0) {
1341 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1342 OptFuncs[I].Disabled = 1;
1345 OptFunc* F = FindOptStep (Name);
1352 void EnableOpt (const char* Name)
1353 /* Enable the optimization with the given name */
1355 if (strcmp (Name, "any") == 0) {
1357 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1358 OptFuncs[I].Disabled = 0;
1361 OptFunc* F = FindOptStep (Name);
1368 void RunOpt (CodeSeg* S)
1369 /* Run the optimizer */
1373 unsigned OptChanges;
1375 /* If we shouldn't run the optimizer, bail out */
1380 /* Print the name of the function we are working on */
1382 Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
1384 Print (stdout, 1, "Running optimizer for global code segment\n");
1387 /* Repeat all steps until there are no more changes */
1389 /* Reset the number of changes */
1392 /* Keep the user hapy */
1393 Print (stdout, 1, " Optimizer pass %u:\n", ++Pass);
1395 /* Run all optimization steps */
1396 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1398 /* Print the name of the following optimizer step */
1399 Print (stdout, 1, " %s:%*s", OptFuncs[I].Name,
1400 (int) (30-strlen(OptFuncs[I].Name)), "");
1402 /* Check if the step is disabled */
1403 if (OptFuncs[I].Disabled) {
1404 Print (stdout, 1, "Disabled\n");
1406 unsigned Changes = OptFuncs[I].Func (S);
1407 OptChanges += Changes;
1408 Print (stdout, 1, "%u Changes\n", Changes);
1412 } while (OptChanges > 0);