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 = CS_GetEntry (S, I);
166 /* Replace the conditional branch */
170 CE_ReplaceOPC (E, OP65_JEQ);
174 CE_ReplaceOPC (E, OP65_JNE);
183 if ((N = CS_GetNextEntry (S, I)) == 0) {
185 Internal ("Invalid program flow");
187 L = CS_GenLabel (S, N);
188 N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
189 CS_InsertEntry (S, N, I);
190 CE_ReplaceOPC (E, OP65_JPL);
194 CE_ReplaceOPC (E, OP65_JPL);
198 CE_ReplaceOPC (E, OP65_JMI);
206 CE_ReplaceOPC (E, OP65_JMI);
208 N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
209 CS_InsertEntry (S, N, I+1);
218 if ((N = CS_GetNextEntry (S, I)) == 0) {
220 Internal ("Invalid program flow");
222 L = CS_GenLabel (S, N);
223 N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
224 CS_InsertEntry (S, N, I);
225 CE_ReplaceOPC (E, OP65_JCS);
229 CE_ReplaceOPC (E, OP65_JCS);
233 CE_ReplaceOPC (E, OP65_JCC);
241 CE_ReplaceOPC (E, OP65_JCC);
243 N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
244 CS_InsertEntry (S, N, I+1);
248 Internal ("Unknown jump condition: %d", Cond);
256 static int IsBitOp (const CodeEntry* E)
257 /* Check if E is one of the bit operations (and, or, eor) */
259 return (E->OPC == OP65_AND || E->OPC == OP65_ORA || E->OPC == OP65_EOR);
264 static int IsCmpToZero (const CodeEntry* E)
265 /* Check if the given instrcuction is a compare to zero instruction */
267 return (E->OPC == OP65_CMP &&
269 (E->Flags & CEF_NUMARG) != 0 &&
275 static int IsSpLoad (const CodeEntry* E)
276 /* Return true if this is the load of A from the stack */
278 return E->OPC == OP65_LDA && E->AM == AM65_ZP_INDY && strcmp (E->Arg, "sp") == 0;
283 static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
284 CodeEntry** L, unsigned Count)
285 /* Check if a 16 bit load of a local variable follows:
293 * If so, read Count entries following the first ldy into L and return true
294 * if this is possible. Otherwise return false.
297 /* Be sure we read enough entries for the check */
300 /* Read the first entry */
301 L[0] = CS_GetEntry (S, Index);
303 /* Check for the sequence */
304 return (L[0]->OPC == OP65_LDY &&
305 L[0]->AM == AM65_IMM &&
306 (L[0]->Flags & CEF_NUMARG) != 0 &&
307 CS_GetEntries (S, L+1, Index+1, Count-1) &&
309 !CE_HasLabel (L[1]) &&
310 L[2]->OPC == OP65_TAX &&
311 !CE_HasLabel (L[2]) &&
312 L[3]->OPC == OP65_DEY &&
313 !CE_HasLabel (L[3]) &&
315 !CE_HasLabel (L[4]));
320 static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
321 /* Check if the instructions at L are an immidiate compare of a/x:
326 return (L[0]->OPC == OP65_CPX &&
327 L[0]->AM == AM65_IMM &&
328 (L[0]->Flags & CEF_NUMARG) != 0 &&
329 !CE_HasLabel (L[0]) &&
330 (L[1]->OPC == OP65_JNE || L[1]->OPC == OP65_BNE) &&
332 !CE_HasLabel (L[1]) &&
333 L[2]->OPC == OP65_CMP &&
334 L[2]->AM == AM65_IMM &&
335 (L[2]->Flags & CEF_NUMARG) != 0 &&
336 (L[3]->Info & OF_ZBRA) != 0 &&
338 (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
343 /*****************************************************************************/
344 /* Remove calls to the bool transformer subroutines */
345 /*****************************************************************************/
349 static unsigned OptBoolTransforms (CodeSeg* S)
350 /* Try to remove the call to boolean transformer routines where the call is
354 unsigned Changes = 0;
356 /* Walk over the entries */
358 while (I < CS_GetEntryCount (S)) {
364 CodeEntry* E = CS_GetEntry (S, I);
366 /* Check for a boolean transformer */
367 if (E->OPC == OP65_JSR &&
368 (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
369 (N = CS_GetNextEntry (S, I)) != 0 &&
370 (N->Info & OF_ZBRA) != 0) {
372 /* Make the boolean transformer unnecessary by changing the
373 * the conditional jump to evaluate the condition flags that
374 * are set after the compare directly. Note: jeq jumps if
375 * the condition is not met, jne jumps if the condition is met.
376 * Invert the code if we jump on condition not met.
378 if (GetBranchCond (N->OPC) == BC_EQ) {
379 /* Jumps if condition false, invert condition */
380 Cond = CmpInvertTab [Cond];
383 /* Check if we can replace the code by something better */
384 ReplaceCmp (S, I+1, Cond);
386 /* Remove the call to the bool transformer */
389 /* Remember, we had changes */
399 /* Return the number of changes made */
405 /*****************************************************************************/
406 /* Optimize subtractions */
407 /*****************************************************************************/
411 static unsigned OptSub1 (CodeSeg* S)
412 /* Search for the sequence
419 * and remove the handling of the high byte if X is not used later.
422 unsigned Changes = 0;
424 /* Walk over the entries */
426 while (I < CS_GetEntryCount (S)) {
431 CodeEntry* E = CS_GetEntry (S, I);
433 /* Check for the sequence */
434 if (E->OPC == OP65_SBC &&
435 CS_GetEntries (S, L, I+1, 3) &&
436 (L[0]->OPC == OP65_BCS || L[0]->OPC == OP65_JCS) &&
438 !CE_HasLabel (L[0]) &&
439 L[1]->OPC == OP65_DEX &&
440 !CE_HasLabel (L[1]) &&
441 L[0]->JumpTo->Owner == L[2] &&
442 !RegXUsed (S, I+3)) {
444 /* Remove the bcs/dex */
445 CS_DelEntries (S, I+1, 2);
447 /* Remember, we had changes */
457 /* Return the number of changes made */
463 static unsigned OptSub2 (CodeSeg* S)
464 /* Search for the sequence
481 unsigned Changes = 0;
483 /* Walk over the entries */
485 while (I < CS_GetEntryCount (S)) {
490 CodeEntry* E = CS_GetEntry (S, I);
492 /* Check for the sequence */
493 if (E->OPC == OP65_LDA &&
494 CS_GetEntries (S, L, I+1, 5) &&
495 L[0]->OPC == OP65_SEC &&
496 !CE_HasLabel (L[0]) &&
497 L[1]->OPC == OP65_STA &&
498 strcmp (L[1]->Arg, "tmp1") == 0 &&
499 !CE_HasLabel (L[1]) &&
500 L[2]->OPC == OP65_LDA &&
501 !CE_HasLabel (L[2]) &&
502 L[3]->OPC == OP65_SBC &&
503 strcmp (L[3]->Arg, "tmp1") == 0 &&
504 !CE_HasLabel (L[3]) &&
505 L[4]->OPC == OP65_STA &&
506 strcmp (L[4]->Arg, L[2]->Arg) == 0 &&
507 !CE_HasLabel (L[4])) {
509 /* Remove the store to tmp1 */
510 CS_DelEntry (S, I+2);
512 /* Remove the subtraction */
513 CS_DelEntry (S, I+3);
515 /* Move the lda to the position of the subtraction and change the
518 CS_MoveEntry (S, I, I+3);
519 CE_ReplaceOPC (E, OP65_SBC);
521 /* If the sequence head had a label, move this label back to the
524 if (CE_HasLabel (E)) {
525 CS_MoveLabels (S, E, L[0]);
528 /* Remember, we had changes */
538 /* Return the number of changes made */
544 /*****************************************************************************/
545 /* Optimize additions */
546 /*****************************************************************************/
550 static unsigned OptAdd1 (CodeSeg* S)
551 /* Search for the sequence
558 * and remove the handling of the high byte if X is not used later.
561 unsigned Changes = 0;
563 /* Walk over the entries */
565 while (I < CS_GetEntryCount (S)) {
570 CodeEntry* E = CS_GetEntry (S, I);
572 /* Check for the sequence */
573 if (E->OPC == OP65_ADC &&
574 CS_GetEntries (S, L, I+1, 3) &&
575 (L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
577 !CE_HasLabel (L[0]) &&
578 L[1]->OPC == OP65_INX &&
579 !CE_HasLabel (L[1]) &&
580 L[0]->JumpTo->Owner == L[2] &&
581 !RegXUsed (S, I+3)) {
583 /* Remove the bcs/dex */
584 CS_DelEntries (S, I+1, 2);
586 /* Remember, we had changes */
596 /* Return the number of changes made */
602 /*****************************************************************************/
603 /* Optimizations for compares */
604 /*****************************************************************************/
608 static unsigned OptCmp1 (CodeSeg* S)
609 /* Search for the sequence
621 unsigned Changes = 0;
623 /* Walk over the entries */
625 while (I < CS_GetEntryCount (S)) {
630 CodeEntry* E = CS_GetEntry (S, I);
632 /* Check for the sequence */
633 if (E->OPC == OP65_STX &&
634 CS_GetEntries (S, L, I+1, 2) &&
635 L[0]->OPC == OP65_STX &&
636 strcmp (L[0]->Arg, "tmp1") == 0 &&
637 !CE_HasLabel (L[0]) &&
638 L[1]->OPC == OP65_ORA &&
639 strcmp (L[1]->Arg, "tmp1") == 0 &&
640 !CE_HasLabel (L[1])) {
642 /* Remove the remaining instructions */
643 CS_DelEntries (S, I+1, 2);
645 /* Insert the ora instead */
646 CS_InsertEntry (S, NewCodeEntry (OP65_ORA, E->AM, E->Arg, 0, E->LI), I+1);
648 /* Remember, we had changes */
658 /* Return the number of changes made */
664 static unsigned OptCmp2 (CodeSeg* S)
667 * lda/and/ora/eor ...
671 * and remove the cmp.
674 unsigned Changes = 0;
676 /* Walk over the entries */
678 while (I < CS_GetEntryCount (S)) {
683 CodeEntry* E = CS_GetEntry (S, I);
685 /* Check for the sequence */
686 if ((E->OPC == OP65_LDA || IsBitOp (E)) &&
687 CS_GetEntries (S, L, I+1, 2) &&
688 IsCmpToZero (L[0]) &&
689 !CE_HasLabel (L[0]) &&
690 (L[1]->Info & OF_FBRA) != 0 &&
691 !CE_HasLabel (L[1])) {
693 /* Remove the compare */
694 CS_DelEntry (S, I+1);
696 /* Remember, we had changes */
706 /* Return the number of changes made */
712 static unsigned OptCmp3 (CodeSeg* S)
722 * If a is zero, we may remove the compare. If a and b are both zero, we may
723 * replace it by the sequence
729 * L1 may be either the label at the branch instruction, or the target label
730 * of this instruction.
733 unsigned Changes = 0;
735 /* Walk over the entries */
737 while (I < CS_GetEntryCount (S)) {
742 CodeEntry* E = CS_GetEntry (S, I);
744 /* Check for the sequence */
745 if (E->OPC == OP65_LDA &&
746 CS_GetEntries (S, L, I+1, 5) &&
747 L[0]->OPC == OP65_LDX &&
748 !CE_HasLabel (L[0]) &&
749 IsImmCmp16 (S, L+1)) {
751 if (L[1]->Num == 0 && L[3]->Num == 0) {
752 /* The value is zero, we may use the simple code version. */
753 CE_ReplaceOPC (L[0], OP65_ORA);
754 CS_DelEntries (S, I+2, 3);
756 /* Move the lda instruction after the first branch. This will
757 * improve speed, since the load is delayed after the first
760 CS_MoveEntry (S, I, I+4);
762 /* We will replace the ldx/cpx by lda/cmp */
763 CE_ReplaceOPC (L[0], OP65_LDA);
764 CE_ReplaceOPC (L[1], OP65_CMP);
766 /* Beware: If the first LDA instruction had a label, we have
767 * to move this label to the top of the sequence again.
769 if (CE_HasLabel (E)) {
770 CS_MoveLabels (S, E, L[0]);
783 /* Return the number of changes made */
789 static unsigned OptCmp4 (CodeSeg* S)
790 /* Optimize compares of local variables:
803 unsigned Changes = 0;
805 /* Walk over the entries */
807 while (I < CS_GetEntryCount (S)) {
811 /* Check for the sequence */
812 if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
814 if (L[5]->Num == 0 && L[7]->Num == 0) {
816 /* The value is zero, we may use the simple code version:
823 CE_ReplaceOPC (L[4], OP65_ORA);
824 CS_DelEntries (S, I+5, 3); /* cpx/bne/cmp */
825 CS_DelEntry (S, I+2); /* tax */
829 /* Change the code to just use the A register. Move the load
830 * of the low byte after the first branch if possible:
841 CS_DelEntry (S, I+2); /* tax */
842 CE_ReplaceOPC (L[5], OP65_CMP); /* cpx -> cmp */
843 CS_MoveEntry (S, I+4, I+2); /* cmp */
844 CS_MoveEntry (S, I+5, I+3); /* bne */
856 /* Return the number of changes made */
862 static unsigned OptCmp5 (CodeSeg* S)
863 /* Search for calls to compare subroutines followed by a conditional branch
864 * and replace them by cheaper versions, since the branch means that the
865 * boolean value returned by these routines is not needed (we may also check
866 * that explicitly, but for the current code generator it is always true).
869 unsigned Changes = 0;
871 /* Walk over the entries */
873 while (I < CS_GetEntryCount (S)) {
879 CodeEntry* E = CS_GetEntry (S, I);
881 /* Check for the sequence */
882 if (E->OPC == OP65_JSR &&
883 (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
884 (N = CS_GetNextEntry (S, I)) != 0 &&
885 (N->Info & OF_ZBRA) != 0 &&
888 /* The tos... functions will return a boolean value in a/x and
889 * the Z flag says if this value is zero or not. We will call
890 * a cheaper subroutine instead, one that does not return a
891 * boolean value but only valid flags. Note: jeq jumps if
892 * the condition is not met, jne jumps if the condition is met.
893 * Invert the code if we jump on condition not met.
895 if (GetBranchCond (N->OPC) == BC_EQ) {
896 /* Jumps if condition false, invert condition */
897 Cond = CmpInvertTab [Cond];
900 /* Replace the subroutine call. */
901 E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
902 CS_InsertEntry (S, E, I+1);
905 /* Replace the conditional branch */
906 ReplaceCmp (S, I+1, Cond);
908 /* Remember, we had changes */
918 /* Return the number of changes made */
924 /*****************************************************************************/
925 /* nega optimizations */
926 /*****************************************************************************/
930 static unsigned OptNegA1 (CodeSeg* S)
937 * Remove the ldx if the lda does not use it.
940 unsigned Changes = 0;
942 /* Walk over the entries */
944 while (I < CS_GetEntryCount (S)) {
949 CodeEntry* E = CS_GetEntry (S, I);
951 /* Check for a ldx */
952 if (E->OPC == OP65_LDX &&
954 (E->Flags & CEF_NUMARG) != 0 &&
956 CS_GetEntries (S, L, I+1, 2) &&
957 L[0]->OPC == OP65_LDA &&
958 (L[0]->Use & REG_X) == 0 &&
959 L[1]->OPC == OP65_JSR &&
960 strcmp (L[1]->Arg, "bnega") == 0) {
962 /* Remove the ldx instruction */
965 /* Remember, we had changes */
975 /* Return the number of changes made */
981 static unsigned OptNegA2 (CodeSeg* S)
988 * Adjust the conditional branch and remove the call to the subroutine.
991 unsigned Changes = 0;
993 /* Walk over the entries */
995 while (I < CS_GetEntryCount (S)) {
1000 CodeEntry* E = CS_GetEntry (S, I);
1002 /* Check for the sequence */
1003 if (E->OPC == OP65_LDA &&
1004 CS_GetEntries (S, L, I+1, 2) &&
1005 L[0]->OPC == OP65_JSR &&
1006 strcmp (L[0]->Arg, "bnega") == 0 &&
1007 !CE_HasLabel (L[0]) &&
1008 (L[1]->Info & OF_ZBRA) != 0) {
1010 /* Invert the branch */
1011 CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
1013 /* Delete the subroutine call */
1014 CS_DelEntry (S, I+1);
1016 /* Remember, we had changes */
1026 /* Return the number of changes made */
1032 /*****************************************************************************/
1033 /* negax optimizations */
1034 /*****************************************************************************/
1038 static unsigned OptNegAX1 (CodeSeg* S)
1039 /* Search for the sequence:
1056 unsigned Changes = 0;
1058 /* Walk over the entries */
1060 while (I < CS_GetEntryCount (S)) {
1064 /* Get next entry */
1065 CodeEntry* E = CS_GetEntry (S, I);
1067 /* Check for the sequence */
1068 if (E->OPC == OP65_LDA &&
1069 E->AM == AM65_ZP_INDY &&
1070 CS_GetEntries (S, L, I+1, 5) &&
1071 L[0]->OPC == OP65_TAX &&
1072 L[1]->OPC == OP65_DEY &&
1073 L[2]->OPC == OP65_LDA &&
1074 L[2]->AM == AM65_ZP_INDY &&
1075 strcmp (L[2]->Arg, E->Arg) == 0 &&
1076 !CE_HasLabel (L[2]) &&
1077 L[3]->OPC == OP65_JSR &&
1078 strcmp (L[3]->Arg, "bnegax") == 0 &&
1079 !CE_HasLabel (L[3]) &&
1080 (L[4]->Info & OF_ZBRA) != 0) {
1083 CE_ReplaceOPC (L[2], OP65_ORA);
1085 /* Invert the branch */
1086 CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
1088 /* Delete the entries no longer needed. Beware: Deleting entries
1089 * will change the indices.
1091 CS_DelEntry (S, I+4); /* jsr bnegax */
1092 CS_DelEntry (S, I+1); /* tax */
1094 /* Remember, we had changes */
1104 /* Return the number of changes made */
1110 static unsigned OptNegAX2 (CodeSeg* S)
1111 /* Search for the sequence:
1125 unsigned Changes = 0;
1127 /* Walk over the entries */
1129 while (I < CS_GetEntryCount (S)) {
1133 /* Get next entry */
1134 CodeEntry* E = CS_GetEntry (S, I);
1136 /* Check for the sequence */
1137 if (E->OPC == OP65_LDA &&
1138 CS_GetEntries (S, L, I+1, 3) &&
1139 L[0]->OPC == OP65_LDX &&
1140 !CE_HasLabel (L[0]) &&
1141 L[1]->OPC == OP65_JSR &&
1142 strcmp (L[1]->Arg, "bnegax") == 0 &&
1143 !CE_HasLabel (L[1]) &&
1144 (L[2]->Info & OF_ZBRA) != 0) {
1147 CE_ReplaceOPC (L[0], OP65_ORA);
1149 /* Invert the branch */
1150 CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
1152 /* Delete the subroutine call */
1153 CS_DelEntry (S, I+2);
1155 /* Remember, we had changes */
1165 /* Return the number of changes made */
1171 static unsigned OptNegAX3 (CodeSeg* S)
1172 /* Search for the sequence:
1178 * and replace it by:
1185 unsigned Changes = 0;
1187 /* Walk over the entries */
1189 while (I < CS_GetEntryCount (S)) {
1193 /* Get next entry */
1194 CodeEntry* E = CS_GetEntry (S, I);
1196 /* Check for the sequence */
1197 if (E->OPC == OP65_JSR &&
1199 CS_GetEntries (S, L, I+1, 2) &&
1200 L[0]->OPC == OP65_JSR &&
1201 strncmp (L[0]->Arg,"bnega",5) == 0 &&
1202 !CE_HasLabel (L[0]) &&
1203 (L[1]->Info & OF_ZBRA) != 0) {
1207 /* Check if we're calling bnega or bnegax */
1208 int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
1210 /* Insert apropriate test code */
1213 X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
1214 CS_InsertEntry (S, X, I+2);
1217 X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
1218 CS_InsertEntry (S, X, I+2);
1219 X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
1220 CS_InsertEntry (S, X, I+3);
1223 /* Delete the subroutine call */
1224 CS_DelEntry (S, I+1);
1226 /* Invert the branch */
1227 CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
1229 /* Remember, we had changes */
1239 /* Return the number of changes made */
1245 /*****************************************************************************/
1247 /*****************************************************************************/
1251 /* Table with all the optimization functions */
1252 typedef struct OptFunc OptFunc;
1254 unsigned (*Func) (CodeSeg*);/* Optimizer function */
1255 const char* Name; /* Name of optimizer step */
1256 char Disabled; /* True if pass disabled */
1261 /* Table with optimizer steps - are called in this order */
1262 static OptFunc OptFuncs [] = {
1263 /* Optimize subtractions */
1264 { OptSub1, "OptSub1", 0 },
1265 { OptSub2, "OptSub2", 0 },
1266 /* Optimize additions */
1267 { OptAdd1, "OptAdd1", 0 },
1268 /* Optimize jump cascades */
1269 { OptJumpCascades, "OptJumpCascades", 0 },
1270 /* Remove dead jumps */
1271 { OptDeadJumps, "OptDeadJumps", 0 },
1272 /* Change jsr/rts to jmp */
1273 { OptRTS, "OptRTS", 0 },
1274 /* Remove dead code */
1275 { OptDeadCode, "OptDeadCode", 0 },
1276 /* Optimize jump targets */
1277 { OptJumpTarget, "OptJumpTarget", 0 },
1278 /* Optimize conditional branches */
1279 { OptCondBranches, "OptCondBranches", 0 },
1280 /* Replace jumps to RTS by RTS */
1281 { OptRTSJumps, "OptRTSJumps", 0 },
1282 /* Remove calls to the bool transformer subroutines */
1283 { OptBoolTransforms, "OptBoolTransforms", 0 },
1284 /* Optimize calls to nega */
1285 { OptNegA1, "OptNegA1", 0 },
1286 { OptNegA2, "OptNegA2", 0 },
1287 /* Optimize calls to negax */
1288 { OptNegAX1, "OptNegAX1", 0 },
1289 { OptNegAX2, "OptNegAX2", 0 },
1290 { OptNegAX3, "OptNegAX3", 0 },
1291 /* Optimize compares */
1292 { OptCmp1, "OptCmp1", 0 },
1293 { OptCmp2, "OptCmp2", 0 },
1294 { OptCmp3, "OptCmp3", 0 },
1295 { OptCmp4, "OptCmp4", 0 },
1296 { OptCmp5, "OptCmp5", 0 },
1297 /* Remove unused loads */
1298 { OptUnusedLoads, "OptUnusedLoads", 0 },
1299 /* Optimize branch distance */
1300 { OptBranchDist, "OptBranchDist", 0 },
1305 static OptFunc* FindOptStep (const char* Name)
1306 /* Find an optimizer step by name in the table and return a pointer. Print an
1307 * error and call AbEnd if not found.
1312 /* Run all optimization steps */
1313 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1314 if (strcmp (OptFuncs[I].Name, Name) == 0) {
1321 AbEnd ("Optimization step `%s' not found", Name);
1327 void DisableOpt (const char* Name)
1328 /* Disable the optimization with the given name */
1330 if (strcmp (Name, "any") == 0) {
1332 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1333 OptFuncs[I].Disabled = 1;
1336 OptFunc* F = FindOptStep (Name);
1343 void EnableOpt (const char* Name)
1344 /* Enable the optimization with the given name */
1346 if (strcmp (Name, "any") == 0) {
1348 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1349 OptFuncs[I].Disabled = 0;
1352 OptFunc* F = FindOptStep (Name);
1359 void RunOpt (CodeSeg* S)
1360 /* Run the optimizer */
1364 unsigned OptChanges;
1366 /* If we shouldn't run the optimizer, bail out */
1371 /* Print the name of the function we are working on */
1373 Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
1375 Print (stdout, 1, "Running optimizer for global code segment\n");
1378 /* Repeat all steps until there are no more changes */
1380 /* Reset the number of changes */
1383 /* Keep the user hapy */
1384 Print (stdout, 1, " Optimizer pass %u:\n", ++Pass);
1386 /* Run all optimization steps */
1387 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1389 /* Print the name of the following optimizer step */
1390 Print (stdout, 1, " %s:%*s", OptFuncs[I].Name,
1391 (int) (30-strlen(OptFuncs[I].Name)), "");
1393 /* Check if the step is disabled */
1394 if (OptFuncs[I].Disabled) {
1395 Print (stdout, 1, "Disabled\n");
1397 unsigned Changes = OptFuncs[I].Func (S);
1398 OptChanges += Changes;
1399 Print (stdout, 1, "%u Changes\n", Changes);
1403 } while (OptChanges > 0);