1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* coptsub.c */ |
4 | /* */ |
5 | /* Optimize subtraction sequences */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2006, Ullrich von Bassewitz */ |
10 | /* Römerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
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. */ |
18 | /* */ |
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: */ |
22 | /* */ |
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 */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | /* common */ |
37 | #include "chartype.h" |
38 | |
39 | /* cc65 */ |
40 | #include "codeent.h" |
41 | #include "codeinfo.h" |
42 | #include "coptsub.h" |
43 | |
44 | |
45 | |
46 | /*****************************************************************************/ |
47 | /* Optimize subtractions */ |
48 | /*****************************************************************************/ |
49 | |
50 | |
51 | |
52 | unsigned OptSub1 (CodeSeg* S) |
53 | /* Search for the sequence |
54 | ** |
55 | ** sbc ... |
56 | ** bcs L |
57 | ** dex |
58 | ** L: |
59 | ** |
60 | ** and remove the handling of the high byte if X is not used later. |
61 | */ |
62 | { |
63 | unsigned Changes = 0; |
64 | |
65 | /* Walk over the entries */ |
66 | unsigned I = 0; |
67 | while (I < CS_GetEntryCount (S)) { |
68 | |
69 | CodeEntry* L[3]; |
70 | |
71 | /* Get next entry */ |
72 | CodeEntry* E = CS_GetEntry (S, I); |
73 | |
74 | /* Check for the sequence */ |
75 | if (E->OPC == OP65_SBC && |
76 | CS_GetEntries (S, L, I+1, 3) && |
77 | (L[0]->OPC == OP65_BCS || L[0]->OPC == OP65_JCS) && |
78 | L[0]->JumpTo != 0 && |
79 | !CE_HasLabel (L[0]) && |
80 | L[1]->OPC == OP65_DEX && |
81 | !CE_HasLabel (L[1]) && |
82 | L[0]->JumpTo->Owner == L[2] && |
83 | !RegXUsed (S, I+3)) { |
84 | |
85 | /* Remove the bcs/dex */ |
86 | CS_DelEntries (S, I+1, 2); |
87 | |
88 | /* Remember, we had changes */ |
89 | ++Changes; |
90 | |
91 | } |
92 | |
93 | /* Next entry */ |
94 | ++I; |
95 | |
96 | } |
97 | |
98 | /* Return the number of changes made */ |
99 | return Changes; |
100 | } |
101 | |
102 | |
103 | |
104 | unsigned OptSub2 (CodeSeg* S) |
105 | /* Search for the sequence |
106 | ** |
107 | ** lda xx |
108 | ** sec |
109 | ** sta tmp1 |
110 | ** lda yy |
111 | ** sbc tmp1 |
112 | ** sta yy |
113 | ** |
114 | ** and replace it by |
115 | ** |
116 | ** sec |
117 | ** lda yy |
118 | ** sbc xx |
119 | ** sta yy |
120 | */ |
121 | { |
122 | unsigned Changes = 0; |
123 | |
124 | /* Walk over the entries */ |
125 | unsigned I = 0; |
126 | while (I < CS_GetEntryCount (S)) { |
127 | |
128 | CodeEntry* L[5]; |
129 | |
130 | /* Get next entry */ |
131 | CodeEntry* E = CS_GetEntry (S, I); |
132 | |
133 | /* Check for the sequence */ |
134 | if (E->OPC == OP65_LDA && |
135 | !CS_RangeHasLabel (S, I+1, 5) && |
136 | CS_GetEntries (S, L, I+1, 5) && |
137 | L[0]->OPC == OP65_SEC && |
138 | L[1]->OPC == OP65_STA && |
139 | strcmp (L[1]->Arg, "tmp1" ) == 0 && |
140 | L[2]->OPC == OP65_LDA && |
141 | L[3]->OPC == OP65_SBC && |
142 | strcmp (L[3]->Arg, "tmp1" ) == 0 && |
143 | L[4]->OPC == OP65_STA && |
144 | strcmp (L[4]->Arg, L[2]->Arg) == 0) { |
145 | |
146 | /* Remove the store to tmp1 */ |
147 | CS_DelEntry (S, I+2); |
148 | |
149 | /* Remove the subtraction */ |
150 | CS_DelEntry (S, I+3); |
151 | |
152 | /* Move the lda to the position of the subtraction and change the |
153 | ** op to SBC. |
154 | */ |
155 | CS_MoveEntry (S, I, I+3); |
156 | CE_ReplaceOPC (E, OP65_SBC); |
157 | |
158 | /* If the sequence head had a label, move this label back to the |
159 | ** head. |
160 | */ |
161 | if (CE_HasLabel (E)) { |
162 | CS_MoveLabels (S, E, L[0]); |
163 | } |
164 | |
165 | /* Remember, we had changes */ |
166 | ++Changes; |
167 | |
168 | } |
169 | |
170 | /* Next entry */ |
171 | ++I; |
172 | |
173 | } |
174 | |
175 | /* Return the number of changes made */ |
176 | return Changes; |
177 | } |
178 | |
179 | |
180 | |
181 | unsigned OptSub3 (CodeSeg* S) |
182 | /* Search for a call to decaxn and replace it by an 8 bit sub if the X register |
183 | ** is not used later. |
184 | */ |
185 | { |
186 | unsigned Changes = 0; |
187 | |
188 | /* Walk over the entries */ |
189 | unsigned I = 0; |
190 | while (I < CS_GetEntryCount (S)) { |
191 | |
192 | CodeEntry* E; |
193 | |
194 | /* Get next entry */ |
195 | E = CS_GetEntry (S, I); |
196 | |
197 | /* Check for the sequence */ |
198 | if (E->OPC == OP65_JSR && |
199 | strncmp (E->Arg, "decax" , 5) == 0 && |
200 | IsDigit (E->Arg[5]) && |
201 | E->Arg[6] == '\0' && |
202 | !RegXUsed (S, I+1)) { |
203 | |
204 | CodeEntry* X; |
205 | const char* Arg; |
206 | |
207 | /* Insert new code behind the sequence */ |
208 | X = NewCodeEntry (OP65_SEC, AM65_IMP, 0, 0, E->LI); |
209 | CS_InsertEntry (S, X, I+1); |
210 | |
211 | Arg = MakeHexArg (E->Arg[5] - '0'); |
212 | X = NewCodeEntry (OP65_SBC, AM65_IMM, Arg, 0, E->LI); |
213 | CS_InsertEntry (S, X, I+2); |
214 | |
215 | /* Delete the old code */ |
216 | CS_DelEntry (S, I); |
217 | |
218 | /* Remember, we had changes */ |
219 | ++Changes; |
220 | |
221 | } |
222 | |
223 | /* Next entry */ |
224 | ++I; |
225 | |
226 | } |
227 | |
228 | /* Return the number of changes made */ |
229 | return Changes; |
230 | } |
231 | |