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 int 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 int IsUnsignedCmp (int Code)
153 /* Check if this is an unsigned compare */
156 return CmpSignedTab [Code] == 0;
161 static const char* MakeBoolCmp (cmp_t Cond)
162 /* Create the name of a bool transformer subroutine for the given code. The
163 * result is placed into a static buffer, so beware!
166 static char Buffer[20];
167 CHECK (Cond != CMP_INV);
168 sprintf (Buffer, "bool%s", CmpSuffixTab[Cond]);
174 static const char* MakeTosCmp (cmp_t Cond)
175 /* Create the name of a tos compare subroutine for the given code. The
176 * result is placed into a static buffer, so beware!
179 static char Buffer[20];
180 CHECK (Cond != CMP_INV);
181 sprintf (Buffer, "tos%sax", CmpSuffixTab[Cond]);
187 static int IsBitOp (const CodeEntry* E)
188 /* Check if E is one of the bit operations (and, or, eor) */
190 return (E->OPC == OPC_AND || E->OPC == OPC_ORA || E->OPC == OPC_EOR);
195 static int IsCmpToZero (const CodeEntry* E)
196 /* Check if the given instrcuction is a compare to zero instruction */
198 return (E->OPC == OPC_CMP &&
200 (E->Flags & CEF_NUMARG) != 0 &&
206 static int IsSpLoad (const CodeEntry* E)
207 /* Return true if this is the load of A from the stack */
209 return E->OPC == OPC_LDA && E->AM == AM_ZP_INDY && strcmp (E->Arg, "sp") == 0;
214 static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
215 CodeEntry** L, unsigned Count)
216 /* Check if a 16 bit load of a local variable follows:
224 * If so, read Count entries following the first ldy into L and return true
225 * if this is possible. Otherwise return false.
228 /* Be sure we read enough entries for the check */
231 /* Read the first entry */
232 L[0] = GetCodeEntry (S, Index);
234 /* Check for the sequence */
235 return (L[0]->OPC == OPC_LDY &&
236 L[0]->AM == AM_IMM &&
237 (L[0]->Flags & CEF_NUMARG) != 0 &&
238 GetCodeEntries (S, L+1, Index+1, Count-1) &&
240 !CodeEntryHasLabel (L[1]) &&
241 L[2]->OPC == OPC_TAX &&
242 !CodeEntryHasLabel (L[2]) &&
243 L[3]->OPC == OPC_DEY &&
244 !CodeEntryHasLabel (L[3]) &&
246 !CodeEntryHasLabel (L[4]));
251 static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
252 /* Check if the instructions at L are an immidiate compare of a/x:
257 return (L[0]->OPC == OPC_CPX &&
258 L[0]->AM == AM_IMM &&
259 (L[0]->Flags & CEF_NUMARG) != 0 &&
260 !CodeEntryHasLabel (L[0]) &&
261 (L[1]->OPC == OPC_JNE || L[1]->OPC == OPC_BNE) &&
263 !CodeEntryHasLabel (L[1]) &&
264 L[2]->OPC == OPC_CMP &&
265 L[2]->AM == AM_IMM &&
266 (L[2]->Flags & CEF_NUMARG) != 0 &&
267 (L[3]->Info & OF_ZBRA) != 0 &&
269 (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
274 /*****************************************************************************/
275 /* Remove calls to the bool transformer subroutines */
276 /*****************************************************************************/
280 static unsigned OptBoolTransforms (CodeSeg* S)
281 /* Try to remove the call to boolean transformer routines where the call is
285 unsigned Changes = 0;
287 /* Walk over the entries */
289 while (I < GetCodeEntryCount (S)) {
295 CodeEntry* E = GetCodeEntry (S, I);
297 /* Check for a boolean transformer */
298 if (E->OPC == OPC_JSR &&
299 (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
300 (N = GetNextCodeEntry (S, I)) != 0 &&
301 (N->Info & OF_ZBRA) != 0) {
306 /* Make the boolean transformer unnecessary by changing the
307 * the conditional jump to evaluate the condition flags that
308 * are set after the compare directly. Note: jeq jumps if
309 * the condition is not met, jne jumps if the condition is met.
310 * Invert the code if we jump on condition not met.
312 if (GetBranchCond (N->OPC) == BC_EQ) {
313 /* Jumps if condition false, invert condition */
314 Cond = CmpInvertTab [Cond];
317 /* Check if we can replace the code by something better */
321 ReplaceOPC (N, OPC_JEQ);
325 ReplaceOPC (N, OPC_JNE);
334 if ((X = GetNextCodeEntry (S, I+1)) == 0) {
338 L = GenCodeLabel (S, X);
339 X = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L);
340 InsertCodeEntry (S, X, I+1);
341 ReplaceOPC (N, OPC_JPL);
345 ReplaceOPC (N, OPC_JPL);
349 ReplaceOPC (N, OPC_JMI);
357 ReplaceOPC (N, OPC_JMI);
359 X = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L);
360 InsertCodeEntry (S, X, I+2);
369 if ((X = GetNextCodeEntry (S, I+1)) == 0) {
373 L = GenCodeLabel (S, X);
374 X = NewCodeEntry (OPC_BEQ, AM_BRA, L->Name, L);
375 InsertCodeEntry (S, X, I+1);
376 ReplaceOPC (N, OPC_JCS);
380 ReplaceOPC (N, OPC_JCS);
384 ReplaceOPC (N, OPC_JCC);
392 ReplaceOPC (N, OPC_JCC);
394 X = NewCodeEntry (OPC_JEQ, AM_BRA, L->Name, L);
395 InsertCodeEntry (S, X, I+2);
399 Internal ("Unknown jump condition: %d", Cond);
403 /* Remove the call to the bool transformer */
406 /* Remember, we had changes */
417 /* Return the number of changes made */
423 /*****************************************************************************/
424 /* Optimize subtractions */
425 /*****************************************************************************/
429 static unsigned OptSub1 (CodeSeg* S)
430 /* Search for the sequence
437 * and remove the handling of the high byte if X is not used later.
440 unsigned Changes = 0;
442 /* Walk over the entries */
444 while (I < GetCodeEntryCount (S)) {
449 CodeEntry* E = GetCodeEntry (S, I);
451 /* Check for the sequence */
452 if (E->OPC == OPC_SBC &&
453 GetCodeEntries (S, L, I+1, 3) &&
454 (L[0]->OPC == OPC_BCS || L[0]->OPC == OPC_JCS) &&
456 !CodeEntryHasLabel (L[0]) &&
457 L[1]->OPC == OPC_DEX &&
458 !CodeEntryHasLabel (L[1]) &&
459 L[0]->JumpTo->Owner == L[2] &&
460 !RegXUsed (S, I+3)) {
462 /* Remove the bcs/dex */
463 DelCodeEntries (S, I+1, 2);
465 /* Remember, we had changes */
475 /* Return the number of changes made */
481 static unsigned OptSub2 (CodeSeg* S)
482 /* Search for the sequence
499 unsigned Changes = 0;
501 /* Walk over the entries */
503 while (I < GetCodeEntryCount (S)) {
508 CodeEntry* E = GetCodeEntry (S, I);
510 /* Check for the sequence */
511 if (E->OPC == OPC_LDA &&
512 GetCodeEntries (S, L, I+1, 5) &&
513 L[0]->OPC == OPC_SEC &&
514 !CodeEntryHasLabel (L[0]) &&
515 L[1]->OPC == OPC_STA &&
516 strcmp (L[1]->Arg, "tmp1") == 0 &&
517 !CodeEntryHasLabel (L[1]) &&
518 L[2]->OPC == OPC_LDA &&
519 !CodeEntryHasLabel (L[2]) &&
520 L[3]->OPC == OPC_SBC &&
521 strcmp (L[3]->Arg, "tmp1") == 0 &&
522 !CodeEntryHasLabel (L[3]) &&
523 L[4]->OPC == OPC_STA &&
524 strcmp (L[4]->Arg, L[2]->Arg) == 0 &&
525 !CodeEntryHasLabel (L[4])) {
527 /* Remove the store to tmp1 */
528 DelCodeEntry (S, I+2);
530 /* Remove the subtraction */
531 DelCodeEntry (S, I+3);
533 /* Move the lda to the position of the subtraction and change the
536 MoveCodeEntry (S, I, I+3);
537 ReplaceOPC (E, OPC_SBC);
539 /* Remember, we had changes */
549 /* Return the number of changes made */
555 /*****************************************************************************/
556 /* Optimize additions */
557 /*****************************************************************************/
561 static unsigned OptAdd1 (CodeSeg* S)
562 /* Search for the sequence
569 * and remove the handling of the high byte if X is not used later.
572 unsigned Changes = 0;
574 /* Walk over the entries */
576 while (I < GetCodeEntryCount (S)) {
581 CodeEntry* E = GetCodeEntry (S, I);
583 /* Check for the sequence */
584 if (E->OPC == OPC_ADC &&
585 GetCodeEntries (S, L, I+1, 3) &&
586 (L[0]->OPC == OPC_BCC || L[0]->OPC == OPC_JCC) &&
588 !CodeEntryHasLabel (L[0]) &&
589 L[1]->OPC == OPC_INX &&
590 !CodeEntryHasLabel (L[1]) &&
591 L[0]->JumpTo->Owner == L[2] &&
592 !RegXUsed (S, I+3)) {
594 /* Remove the bcs/dex */
595 DelCodeEntries (S, I+1, 2);
597 /* Remember, we had changes */
607 /* Return the number of changes made */
613 /*****************************************************************************/
614 /* Optimizations for compares */
615 /*****************************************************************************/
619 static unsigned OptCmp1 (CodeSeg* S)
620 /* Search for the sequence
632 unsigned Changes = 0;
634 /* Walk over the entries */
636 while (I < GetCodeEntryCount (S)) {
641 CodeEntry* E = GetCodeEntry (S, I);
643 /* Check for the sequence */
644 if (E->OPC == OPC_STX &&
645 GetCodeEntries (S, L, I+1, 2) &&
646 L[0]->OPC == OPC_STX &&
647 strcmp (L[0]->Arg, "tmp1") == 0 &&
648 !CodeEntryHasLabel (L[0]) &&
649 L[1]->OPC == OPC_ORA &&
650 strcmp (L[1]->Arg, "tmp1") == 0 &&
651 !CodeEntryHasLabel (L[1])) {
653 /* Remove the remaining instructions */
654 DelCodeEntries (S, I+1, 2);
656 /* Insert the ora instead */
657 InsertCodeEntry (S, NewCodeEntry (OPC_ORA, E->AM, E->Arg, 0), I+1);
659 /* Remember, we had changes */
669 /* Return the number of changes made */
675 static unsigned OptCmp2 (CodeSeg* S)
678 * lda/and/ora/eor ...
682 * and remove the cmp.
685 unsigned Changes = 0;
687 /* Walk over the entries */
689 while (I < GetCodeEntryCount (S)) {
694 CodeEntry* E = GetCodeEntry (S, I);
696 /* Check for the sequence */
697 if ((E->OPC == OPC_LDA || IsBitOp (E)) &&
698 GetCodeEntries (S, L, I+1, 2) &&
699 IsCmpToZero (L[0]) &&
700 !CodeEntryHasLabel (L[0]) &&
701 (L[1]->Info & OF_FBRA) != 0 &&
702 !CodeEntryHasLabel (L[1])) {
704 /* Remove the compare */
705 DelCodeEntry (S, I+1);
707 /* Remember, we had changes */
717 /* Return the number of changes made */
723 static unsigned OptCmp3 (CodeSeg* S)
733 * If a is zero, we may remove the compare. If a and b are both zero, we may
734 * replace it by the sequence
740 * L1 may be either the label at the branch instruction, or the target label
741 * of this instruction.
744 unsigned Changes = 0;
746 /* Walk over the entries */
748 while (I < GetCodeEntryCount (S)) {
753 CodeEntry* E = GetCodeEntry (S, I);
755 /* Check for the sequence */
756 if (E->OPC == OPC_LDA &&
757 GetCodeEntries (S, L, I+1, 5) &&
758 L[0]->OPC == OPC_LDX &&
759 !CodeEntryHasLabel (L[0]) &&
760 IsImmCmp16 (S, L+1)) {
762 if (L[1]->Num == 0 && L[3]->Num == 0) {
763 /* The value is zero, we may use the simple code version. */
764 ReplaceOPC (L[0], OPC_ORA);
765 DelCodeEntries (S, I+2, 3);
767 /* Move the lda instruction after the first branch. This will
768 * improve speed, since the load is delayed after the first
771 MoveCodeEntry (S, I, I+4);
773 /* We will replace the ldx/cpx by lda/cmp */
774 ReplaceOPC (L[0], OPC_LDA);
775 ReplaceOPC (L[1], OPC_CMP);
787 /* Return the number of changes made */
793 static unsigned OptCmp4 (CodeSeg* S)
794 /* Optimize compares of local variables:
807 unsigned Changes = 0;
809 /* Walk over the entries */
811 while (I < GetCodeEntryCount (S)) {
815 /* Check for the sequence */
816 if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
818 if (L[5]->Num == 0 && L[7]->Num == 0) {
820 /* The value is zero, we may use the simple code version:
827 ReplaceOPC (L[4], OPC_ORA);
828 DelCodeEntries (S, I+5, 3); /* cpx/bne/cmp */
829 DelCodeEntry (S, I+2); /* tax */
833 /* Change the code to just use the A register. Move the load
834 * of the low byte after the first branch if possible:
845 DelCodeEntry (S, I+2); /* tax */
846 ReplaceOPC (L[5], OPC_CMP); /* cpx -> cmp */
847 MoveCodeEntry (S, I+4, I+2); /* cmp */
848 MoveCodeEntry (S, I+5, I+3); /* bne */
860 /* Return the number of changes made */
866 /*****************************************************************************/
867 /* nega optimizations */
868 /*****************************************************************************/
872 static unsigned OptNegA1 (CodeSeg* S)
879 * Remove the ldx if the lda does not use it.
882 unsigned Changes = 0;
884 /* Walk over the entries */
886 while (I < GetCodeEntryCount (S)) {
891 CodeEntry* E = GetCodeEntry (S, I);
893 /* Check for a ldx */
894 if (E->OPC == OPC_LDX &&
896 (E->Flags & CEF_NUMARG) != 0 &&
898 GetCodeEntries (S, L, I+1, 2) &&
899 L[0]->OPC == OPC_LDA &&
900 (L[0]->Use & REG_X) == 0 &&
901 L[1]->OPC == OPC_JSR &&
902 strcmp (L[1]->Arg, "bnega") == 0) {
904 /* Remove the ldx instruction */
907 /* Remember, we had changes */
917 /* Return the number of changes made */
923 static unsigned OptNegA2 (CodeSeg* S)
930 * Adjust the conditional branch and remove the call to the subroutine.
933 unsigned Changes = 0;
935 /* Walk over the entries */
937 while (I < GetCodeEntryCount (S)) {
942 CodeEntry* E = GetCodeEntry (S, I);
944 /* Check for the sequence */
945 if (E->OPC == OPC_LDA &&
946 GetCodeEntries (S, L, I+1, 2) &&
947 L[0]->OPC == OPC_JSR &&
948 strcmp (L[0]->Arg, "bnega") == 0 &&
949 !CodeEntryHasLabel (L[0]) &&
950 (L[1]->Info & OF_ZBRA) != 0) {
952 /* Invert the branch */
953 ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
955 /* Delete the subroutine call */
956 DelCodeEntry (S, I+1);
958 /* Remember, we had changes */
968 /* Return the number of changes made */
974 /*****************************************************************************/
975 /* negax optimizations */
976 /*****************************************************************************/
980 static unsigned OptNegAX1 (CodeSeg* S)
981 /* Search for the sequence:
998 unsigned Changes = 0;
1000 /* Walk over the entries */
1002 while (I < GetCodeEntryCount (S)) {
1006 /* Get next entry */
1007 CodeEntry* E = GetCodeEntry (S, I);
1009 /* Check for the sequence */
1010 if (E->OPC == OPC_LDA &&
1011 E->AM == AM_ZP_INDY &&
1012 GetCodeEntries (S, L, I+1, 5) &&
1013 L[0]->OPC == OPC_TAX &&
1014 L[1]->OPC == OPC_DEY &&
1015 L[2]->OPC == OPC_LDA &&
1016 L[2]->AM == AM_ZP_INDY &&
1017 strcmp (L[2]->Arg, E->Arg) == 0 &&
1018 !CodeEntryHasLabel (L[2]) &&
1019 L[3]->OPC == OPC_JSR &&
1020 strcmp (L[3]->Arg, "bnegax") == 0 &&
1021 !CodeEntryHasLabel (L[3]) &&
1022 (L[4]->Info & OF_ZBRA) != 0) {
1025 ReplaceOPC (L[2], OPC_ORA);
1027 /* Invert the branch */
1028 ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
1030 /* Delete the entries no longer needed. Beware: Deleting entries
1031 * will change the indices.
1033 DelCodeEntry (S, I+4); /* jsr bnegax */
1034 DelCodeEntry (S, I+1); /* tax */
1036 /* Remember, we had changes */
1046 /* Return the number of changes made */
1052 static unsigned OptNegAX2 (CodeSeg* S)
1053 /* Search for the sequence:
1067 unsigned Changes = 0;
1069 /* Walk over the entries */
1071 while (I < GetCodeEntryCount (S)) {
1075 /* Get next entry */
1076 CodeEntry* E = GetCodeEntry (S, I);
1078 /* Check for the sequence */
1079 if (E->OPC == OPC_LDA &&
1080 GetCodeEntries (S, L, I+1, 3) &&
1081 L[0]->OPC == OPC_LDX &&
1082 !CodeEntryHasLabel (L[0]) &&
1083 L[1]->OPC == OPC_JSR &&
1084 strcmp (L[1]->Arg, "bnegax") == 0 &&
1085 !CodeEntryHasLabel (L[1]) &&
1086 (L[2]->Info & OF_ZBRA) != 0) {
1089 ReplaceOPC (L[0], OPC_ORA);
1091 /* Invert the branch */
1092 ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
1094 /* Delete the subroutine call */
1095 DelCodeEntry (S, I+2);
1097 /* Remember, we had changes */
1107 /* Return the number of changes made */
1113 static unsigned OptNegAX3 (CodeSeg* S)
1114 /* Search for the sequence:
1120 * and replace it by:
1127 unsigned Changes = 0;
1129 /* Walk over the entries */
1131 while (I < GetCodeEntryCount (S)) {
1135 /* Get next entry */
1136 CodeEntry* E = GetCodeEntry (S, I);
1138 /* Check for the sequence */
1139 if (E->OPC == OPC_JSR &&
1141 GetCodeEntries (S, L, I+1, 2) &&
1142 L[0]->OPC == OPC_JSR &&
1143 strncmp (L[0]->Arg,"bnega",5) == 0 &&
1144 !CodeEntryHasLabel (L[0]) &&
1145 (L[1]->Info & OF_ZBRA) != 0) {
1147 /* Check if we're calling bnega or bnegax */
1148 int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
1150 /* Delete the subroutine call */
1151 DelCodeEntry (S, I+1);
1153 /* Insert apropriate test code */
1156 InsertCodeEntry (S, NewCodeEntry (OPC_TAX, AM_IMP, 0, 0), I+1);
1159 InsertCodeEntry (S, NewCodeEntry (OPC_STX, AM_ZP, "tmp1", 0), I+1);
1160 InsertCodeEntry (S, NewCodeEntry (OPC_ORA, AM_ZP, "tmp1", 0), I+2);
1163 /* Invert the branch */
1164 ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
1166 /* Remember, we had changes */
1176 /* Return the number of changes made */
1182 /*****************************************************************************/
1184 /*****************************************************************************/
1188 /* Table with all the optimization functions */
1189 typedef struct OptFunc OptFunc;
1191 unsigned (*Func) (CodeSeg*);/* Optimizer function */
1192 const char* Name; /* Name of optimizer step */
1193 char Disabled; /* True if pass disabled */
1198 /* Table with optimizer steps - are called in this order */
1199 static OptFunc OptFuncs [] = {
1200 /* Optimize subtractions */
1201 { OptSub1, "OptSub1", 0 },
1202 { OptSub2, "OptSub2", 0 },
1203 /* Optimize additions */
1204 { OptAdd1, "OptAdd1", 0 },
1205 /* Optimize jump cascades */
1206 { OptJumpCascades, "OptJumpCascades", 0 },
1207 /* Remove dead jumps */
1208 { OptDeadJumps, "OptDeadJumps", 0 },
1209 /* Change jsr/rts to jmp */
1210 { OptRTS, "OptRTS", 0 },
1211 /* Remove dead code */
1212 { OptDeadCode, "OptDeadCode", 0 },
1213 /* Optimize jump targets */
1214 { OptJumpTarget, "OptJumpTarget", 0 },
1215 /* Optimize conditional branches */
1216 { OptCondBranches, "OptCondBranches", 0 },
1217 /* Replace jumps to RTS by RTS */
1218 { OptRTSJumps, "OptRTSJumps", 0 },
1219 /* Remove calls to the bool transformer subroutines */
1220 { OptBoolTransforms, "OptBoolTransforms", 0 },
1221 /* Optimize calls to nega */
1222 { OptNegA1, "OptNegA1", 0 },
1223 { OptNegA2, "OptNegA2", 0 },
1224 /* Optimize calls to negax */
1225 { OptNegAX1, "OptNegAX1", 0 },
1226 { OptNegAX2, "OptNegAX2", 0 },
1227 { OptNegAX3, "OptNegAX3", 0 },
1228 /* Optimize compares */
1229 { OptCmp1, "OptCmp1", 0 },
1230 { OptCmp2, "OptCmp2", 0 },
1231 { OptCmp3, "OptCmp3", 0 },
1232 { OptCmp4, "OptCmp4", 0 },
1233 /* Remove unused loads */
1234 { OptUnusedLoads, "OptUnusedLoads", 0 },
1235 /* Optimize branch distance */
1236 { OptBranchDist, "OptBranchDist", 0 },
1241 static OptFunc* FindOptStep (const char* Name)
1242 /* Find an optimizer step by name in the table and return a pointer. Print an
1243 * error and call AbEnd if not found.
1248 /* Run all optimization steps */
1249 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1250 if (strcmp (OptFuncs[I].Name, Name) == 0) {
1257 AbEnd ("Optimization step `%s' not found", Name);
1263 void DisableOpt (const char* Name)
1264 /* Disable the optimization with the given name */
1266 OptFunc* F = FindOptStep (Name);
1272 void EnableOpt (const char* Name)
1273 /* Enable the optimization with the given name */
1275 OptFunc* F = FindOptStep (Name);
1281 void RunOpt (CodeSeg* S)
1282 /* Run the optimizer */
1286 unsigned OptChanges;
1288 /* If we shouldn't run the optimizer, bail out */
1293 /* Print the name of the function we are working on */
1295 Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
1297 Print (stdout, 1, "Running optimizer for global code segment\n");
1300 /* Repeat all steps until there are no more changes */
1302 /* Reset the number of changes */
1305 /* Keep the user hapy */
1306 Print (stdout, 1, " Optimizer pass %u:\n", ++Pass);
1308 /* Run all optimization steps */
1309 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
1311 /* Print the name of the following optimizer step */
1312 Print (stdout, 1, " %s:%*s", OptFuncs[I].Name,
1313 (int) (30-strlen(OptFuncs[I].Name)), "");
1315 /* Check if the step is disabled */
1316 if (OptFuncs[I].Disabled) {
1317 Print (stdout, 1, "Disabled\n");
1319 unsigned Changes = OptFuncs[I].Func (S);
1320 OptChanges += Changes;
1321 Print (stdout, 1, "%u Changes\n", Changes);
1325 } while (OptChanges > 0);