1 /*****************************************************************************/
5 /* Optimize addition sequences */
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 /*****************************************************************************/
48 /*****************************************************************************/
49 /* Optimize additions */
50 /*****************************************************************************/
54 unsigned OptAdd1 (CodeSeg* S)
55 /* Search for the sequence
75 /* Walk over the entries */
77 while (I < CS_GetEntryCount (S)) {
82 CodeEntry* E = CS_GetEntry (S, I);
84 /* Check for the sequence */
85 if (E->OPC == OP65_JSR &&
86 strcmp (E->Arg, "pushax") == 0 &&
87 CS_GetEntries (S, L, I+1, 5) &&
88 L[0]->OPC == OP65_LDY &&
90 !CE_HasLabel (L[0]) &&
91 L[1]->OPC == OP65_LDX &&
94 !CE_HasLabel (L[1]) &&
95 L[2]->OPC == OP65_LDA &&
96 !CE_HasLabel (L[2]) &&
97 L[3]->OPC == OP65_JSR &&
98 strcmp (L[3]->Arg, "tosaddax") == 0 &&
99 !CE_HasLabel (L[3])) {
104 /* Remove the call to pushax */
107 /* Correct the stack offset (needed since pushax was removed) */
108 CE_SetNumArg (L[0], L[0]->Num - 2);
111 X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
112 CS_InsertEntry (S, X, I+1);
114 /* Remove the load */
115 CS_DelEntry (S, I+3); /* lda */
116 CS_DelEntry (S, I+2); /* ldx */
119 X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
120 CS_InsertEntry (S, X, I+2);
122 /* Generate the branch label and the branch */
123 Label = CS_GenLabel (S, L[4]);
124 X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI);
125 CS_InsertEntry (S, X, I+3);
127 /* Generate the increment of the high byte */
128 X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI);
129 CS_InsertEntry (S, X, I+4);
131 /* Delete the call to tosaddax */
132 CS_DelEntry (S, I+5);
134 /* Remember, we had changes */
144 /* Return the number of changes made */
150 unsigned OptAdd2 (CodeSeg* S)
151 /* Search for the sequence
175 * provided that a/x is not used later.
178 unsigned Changes = 0;
180 /* Walk over the entries */
182 while (I < CS_GetEntryCount (S)) {
187 L[0] = CS_GetEntry (S, I);
189 /* Check for the sequence */
190 if (L[0]->OPC == OP65_LDY &&
191 CE_KnownImm (L[0]) &&
192 CS_GetEntries (S, L+1, I+1, 6) &&
193 L[1]->OPC == OP65_LDA &&
194 L[1]->AM == AM65_ZP_INDY &&
195 !CE_HasLabel (L[1]) &&
196 L[2]->OPC == OP65_TAX &&
197 !CE_HasLabel (L[2]) &&
198 L[3]->OPC == OP65_DEY &&
199 !CE_HasLabel (L[3]) &&
200 L[4]->OPC == OP65_LDA &&
201 L[4]->AM == AM65_ZP_INDY &&
202 !CE_HasLabel (L[4]) &&
203 L[5]->OPC == OP65_LDY &&
204 CE_KnownImm (L[5]) &&
205 !CE_HasLabel (L[5]) &&
206 L[6]->OPC == OP65_JSR &&
207 strcmp (L[6]->Arg, "addeqysp") == 0 &&
208 !CE_HasLabel (L[6]) &&
209 (GetRegInfo (S, I+7, REG_AX) & REG_AX) == 0) {
215 /* Adjust the operand of the first LDY */
216 CE_SetNumArg (L[0], L[0]->Num - 1);
218 /* Load Y with the low offset of the target variable */
219 X = NewCodeEntry (OP65_LDY, AM65_IMM, L[5]->Arg, 0, L[1]->LI);
220 CS_InsertEntry (S, X, I+2);
223 X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI);
224 CS_InsertEntry (S, X, I+3);
226 /* Remove the TAX/DEY sequence */
227 CS_DelEntry (S, I+5); /* dey */
228 CS_DelEntry (S, I+4); /* tax */
230 /* Addition of the low byte */
231 X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[4]->LI);
232 CS_InsertEntry (S, X, I+4);
233 X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[4]->LI);
234 CS_InsertEntry (S, X, I+5);
237 xsprintf (Buf, sizeof (Buf), "$%02X", (int) (L[0]->Num+1));
238 X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[4]->LI);
239 CS_InsertEntry (S, X, I+6);
241 /* Addition of the high byte */
242 xsprintf (Buf, sizeof (Buf), "$%02X", (int)(L[5]->Num+1));
243 X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[5]->LI);
244 CS_InsertEntry (S, X, I+8);
245 X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[6]->LI);
246 CS_InsertEntry (S, X, I+9);
247 X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[6]->LI);
248 CS_InsertEntry (S, X, I+10);
250 /* Delete the remaining stuff */
251 CS_DelEntry (S, I+12);
252 CS_DelEntry (S, I+11);
254 /* Remember, we had changes */
264 /* Return the number of changes made */
270 unsigned OptAdd3 (CodeSeg* S)
271 /* Search for the sequence
278 * and remove the handling of the high byte if X is not used later.
281 unsigned Changes = 0;
283 /* Walk over the entries */
285 while (I < CS_GetEntryCount (S)) {
290 CodeEntry* E = CS_GetEntry (S, I);
292 /* Check for the sequence */
293 if (E->OPC == OP65_ADC &&
294 CS_GetEntries (S, L, I+1, 3) &&
295 (L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
297 !CE_HasLabel (L[0]) &&
298 L[1]->OPC == OP65_INX &&
299 !CE_HasLabel (L[1]) &&
300 L[0]->JumpTo->Owner == L[2] &&
301 !RegXUsed (S, I+3)) {
303 /* Remove the bcs/dex */
304 CS_DelEntries (S, I+1, 2);
306 /* Remember, we had changes */
316 /* Return the number of changes made */