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 /*****************************************************************************/
49 /*****************************************************************************/
51 /*****************************************************************************/
55 /* Counter for the number of changes in one run. The optimizer process is
56 * repeated until there are no more changes.
58 static unsigned OptChanges;
62 /*****************************************************************************/
63 /* Remove dead jumps */
64 /*****************************************************************************/
68 static void OptDeadJumps (CodeSeg* S)
69 /* Remove dead jumps (jumps to the next instruction) */
74 /* Get the number of entries, bail out if we have less than two entries */
75 unsigned Count = CollCount (&S->Entries);
80 /* Walk over all entries minus the last one */
84 /* Get the next entry */
85 E = CollAt (&S->Entries, I);
87 /* Check if it's a branch, if it has a local target, and if the target
88 * is the next instruction.
90 if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
92 /* Delete the dead jump */
93 DelCodeSegLine (S, I);
95 /* Keep the number of entries updated */
98 /* Remember, we had changes */
112 /*****************************************************************************/
113 /* Remove dead code */
114 /*****************************************************************************/
118 static void OptDeadCode (CodeSeg* S)
119 /* Remove dead code (code that follows an unconditional jump or an rts/rti
125 /* Get the number of entries, bail out if we have less than two entries */
126 unsigned Count = CollCount (&S->Entries);
131 /* Walk over all entries minus the last one */
133 while (I < Count-1) {
136 CodeEntry* E = CollAt (&S->Entries, I);
138 /* Check if it's an unconditional branch, and if the next entry has
141 if ((E->OPC == OPC_JMP || E->OPC == OPC_BRA || E->OPC == OPC_RTS || E->OPC == OPC_RTI) &&
142 !CodeEntryHasLabel (CollAt (&S->Entries, I+1))) {
144 /* Delete the next entry */
145 DelCodeSegLine (S, I+1);
147 /* Keep the number of entries updated */
150 /* Remember, we had changes */
164 /*****************************************************************************/
165 /* Optimize jump cascades */
166 /*****************************************************************************/
170 static void OptJumpCascades (CodeSeg* S)
171 /* Optimize jump cascades (jumps to jumps). In such a case, the jump is
172 * replaced by a jump to the final location. This will in some cases produce
173 * worse code, because some jump targets are no longer reachable by short
174 * branches, but this is quite rare, so there are more advantages than
180 /* Get the number of entries, bail out if we have no entries */
181 unsigned Count = CollCount (&S->Entries);
186 /* Walk over all entries */
194 CodeEntry* E = CollAt (&S->Entries, I);
196 /* Check if it's a branch, if it has a label attached, and if the
197 * instruction at this label is also a branch.
199 if (E->AM == AM_BRA &&
200 (OldLabel = E->JumpTo) != 0 &&
201 OldLabel->Owner->AM == AM_BRA &&
202 (NewLabel = OldLabel->Owner->JumpTo) != 0) {
204 /* Get the instruction that has the new label attached */
205 CodeEntry* N = OldLabel->Owner;
207 /* Remove the reference to our label and delete it if this was
208 * the last reference.
210 if (RemoveLabelRef (OldLabel, E) == 0) {
212 DelCodeLabel (S, OldLabel);
215 /* Remove usage information from the entry and use the usage
216 * information from the new instruction instead.
218 E->Info &= ~(CI_MASK_USE | CI_MASK_CHG);
219 E->Info |= N->Info & ~(CI_MASK_USE | CI_MASK_CHG);
221 /* Use the new label */
222 AddLabelRef (NewLabel, E);
224 /* Remember ,we had changes */
237 /*****************************************************************************/
239 /*****************************************************************************/
243 void RunOpt (CodeSeg* S)
244 /* Run the optimizer */
246 typedef void (*OptFunc) (CodeSeg*);
248 /* Table with optimizer steps - are called in this order */
249 static const OptFunc OptFuncs [] = {
250 OptJumpCascades, /* Optimize jump cascades */
251 OptDeadJumps, /* Remove dead jumps */
252 OptDeadCode, /* Remove dead code */
255 /* Repeat all steps until there are no more changes */
261 /* Reset the number of changes */
264 /* Run all optimization steps */
266 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
267 if ((OptDisable & Flags) == 0) {
269 } else if (Verbosity > 0 || Debug) {
270 printf ("Optimizer pass %u skipped\n", I);
275 } while (OptChanges > 0);