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 /*****************************************************************************/
47 /*****************************************************************************/
49 /*****************************************************************************/
53 /* Counter for the number of changes in one run. The optimizer process is
54 * repeated until there are no more changes.
56 static unsigned OptChanges;
60 /*****************************************************************************/
61 /* Remove dead jumps */
62 /*****************************************************************************/
66 static void OptDeadJumps (CodeSeg* S)
67 /* Remove dead jumps (jumps to the next instruction) */
72 /* Get the number of entries, bail out if we have less than two entries */
73 unsigned Count = CollCount (&S->Entries);
78 /* Walk over all entries minus the last one */
82 /* Get the next entry */
83 E = GetCodeEntry (S, I);
85 /* Check if it's a branch, if it has a local target, and if the target
86 * is the next instruction.
88 if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
90 /* Delete the dead jump */
93 /* Keep the number of entries updated */
96 /* Remember, we had changes */
110 /*****************************************************************************/
111 /* Remove dead code */
112 /*****************************************************************************/
116 static void OptDeadCode (CodeSeg* S)
117 /* Remove dead code (code that follows an unconditional jump or an rts/rti
123 /* Get the number of entries, bail out if we have less than two entries */
124 unsigned Count = CollCount (&S->Entries);
129 /* Walk over all entries minus the last one */
131 while (I < Count-1) {
134 CodeEntry* E = GetCodeEntry (S, I);
136 /* Check if it's an unconditional branch, and if the next entry has
139 if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
141 /* Delete the next entry */
142 DelCodeEntry (S, I+1);
144 /* Keep the number of entries updated */
147 /* Remember, we had changes */
161 /*****************************************************************************/
162 /* Optimize jump cascades */
163 /*****************************************************************************/
167 static void OptJumpCascades (CodeSeg* S)
168 /* Optimize jump cascades (jumps to jumps). In such a case, the jump is
169 * replaced by a jump to the final location. This will in some cases produce
170 * worse code, because some jump targets are no longer reachable by short
171 * branches, but this is quite rare, so there are more advantages than
177 /* Get the number of entries, bail out if we have no entries */
178 unsigned Count = CollCount (&S->Entries);
183 /* Walk over all entries */
191 CodeEntry* E = GetCodeEntry (S, I);
193 /* Check if it's a branch, if it has a label attached, and if the
194 * instruction at this label is also a branch, and (important) if
195 * both instructions are not identical.
197 if (E->AM == AM_BRA && /* It's a branch */
198 (OldLabel = E->JumpTo) != 0 && /* Label attached */
199 OldLabel->Owner->AM == AM_BRA && /* Jumps to a branch.. */
200 (NewLabel = OldLabel->Owner->JumpTo) != 0 && /* ..which has a label */
201 OldLabel->Owner != E) { /* And both are distinct */
203 /* Get the instruction that has the new label attached */
204 CodeEntry* N = OldLabel->Owner;
206 /* Remove the reference to our label and delete it if this was
207 * the last reference.
209 if (RemoveLabelRef (OldLabel, E) == 0) {
211 DelCodeLabel (S, OldLabel);
214 /* Use the usage information from the new instruction */
218 /* Use the new label */
219 AddLabelRef (NewLabel, E);
221 /* Remember ,we had changes */
234 /*****************************************************************************/
235 /* Optimize jsr/rts */
236 /*****************************************************************************/
240 static void OptRTS (CodeSeg* S)
241 /* Optimize subroutine calls followed by an RTS. The subroutine call will get
242 * replaced by a jump. Don't bother to delete the RTS if it does not have a
243 * label, the dead code elimination should take care of it.
248 /* Get the number of entries, bail out if we have less than 2 entries */
249 unsigned Count = CollCount (&S->Entries);
254 /* Walk over all entries minus the last one */
256 while (I < Count-1) {
259 CodeEntry* E = GetCodeEntry (S, I);
261 /* Check if it's a subroutine call and if the following insn is RTS */
262 if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
264 /* Change the jsr to a jmp */
267 /* Change the opcode info to that of the jump */
268 E->Info = GetOPCInfo (OPC_JMP);
270 /* Remember, we had changes */
283 /*****************************************************************************/
284 /* Optimize jump targets */
285 /*****************************************************************************/
289 static void OptJumpTarget (CodeSeg* S)
290 /* If the instruction preceeding an unconditional branch is the same as the
291 * instruction preceeding the jump target, the jump target may be moved
292 * one entry back. This is a size optimization, since the instruction before
293 * the branch gets removed.
298 /* Get the number of entries, bail out if we have not enough */
299 unsigned Count = CollCount (&S->Entries);
304 /* Walk over all entries minus the first one */
308 /* Get this entry and the entry before this one */
309 CodeEntry* E = GetCodeEntry (S, I);
311 /* Check if we have a jump or branch, and a matching label */
312 if ((E->Info & OF_UBRA) != 0 && E->JumpTo) {
314 /* Remember, we had changes */
327 /*****************************************************************************/
329 /*****************************************************************************/
333 void RunOpt (CodeSeg* S)
334 /* Run the optimizer */
336 typedef void (*OptFunc) (CodeSeg*);
338 /* Table with optimizer steps - are called in this order */
339 static const OptFunc OptFuncs [] = {
340 OptJumpCascades, /* Optimize jump cascades */
341 OptDeadJumps, /* Remove dead jumps */
342 OptDeadCode, /* Remove dead code */
343 OptRTS, /* Change jsr/rts to jmp */
346 /* Repeat all steps until there are no more changes */
352 /* Reset the number of changes */
355 /* Run all optimization steps */
357 for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
358 if ((OptDisable & Flags) == 0) {
360 } else if (Verbosity > 0 || Debug) {
361 printf ("Optimizer pass %u skipped\n", I);
366 } while (OptChanges > 0);