1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* codeseg.h */ |
4 | /* */ |
5 | /* Code segment structure */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2001-2009, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 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 | #ifndef CODESEG_H |
37 | #define CODESEG_H |
38 | |
39 | |
40 | |
41 | #include <stdarg.h> |
42 | |
43 | /* common */ |
44 | #include "attrib.h" |
45 | #include "coll.h" |
46 | #include "inline.h" |
47 | |
48 | /* cc65 */ |
49 | #include "codelab.h" |
50 | #include "lineinfo.h" |
51 | #include "symentry.h" |
52 | |
53 | |
54 | |
55 | /*****************************************************************************/ |
56 | /* Forwards */ |
57 | /*****************************************************************************/ |
58 | |
59 | |
60 | |
61 | struct CodeEntry; |
62 | |
63 | |
64 | |
65 | /*****************************************************************************/ |
66 | /* Data */ |
67 | /*****************************************************************************/ |
68 | |
69 | |
70 | |
71 | /* Size of the label hash table */ |
72 | #define CS_LABEL_HASH_SIZE 29 |
73 | |
74 | /* Code segment structure */ |
75 | typedef struct CodeSeg CodeSeg; |
76 | struct CodeSeg { |
77 | char* SegName; /* Segment name */ |
78 | SymEntry* Func; /* Owner function */ |
79 | Collection Entries; /* List of code entries */ |
80 | Collection Labels; /* Labels for next insn */ |
81 | CodeLabel* LabelHash[CS_LABEL_HASH_SIZE]; /* Label hash table */ |
82 | unsigned short ExitRegs; /* Register use on exit */ |
83 | |
84 | /* Optimization settings for this segment */ |
85 | unsigned char Optimize; /* On/off switch */ |
86 | unsigned CodeSizeFactor; |
87 | }; |
88 | |
89 | |
90 | |
91 | /*****************************************************************************/ |
92 | /* Code */ |
93 | /*****************************************************************************/ |
94 | |
95 | |
96 | |
97 | CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func); |
98 | /* Create a new code segment, initialize and return it */ |
99 | |
100 | void CS_AddEntry (CodeSeg* S, struct CodeEntry* E); |
101 | /* Add an entry to the given code segment */ |
102 | |
103 | void CS_AddVLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) attribute ((format(printf,3,0))); |
104 | /* Add a line to the given code segment */ |
105 | |
106 | void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...) attribute ((format(printf,3,4))); |
107 | /* Add a line to the given code segment */ |
108 | |
109 | #if defined(HAVE_INLINE) |
110 | INLINE unsigned CS_GetEntryCount (const CodeSeg* S) |
111 | /* Return the number of entries for the given code segment */ |
112 | { |
113 | return CollCount (&S->Entries); |
114 | } |
115 | #else |
116 | # define CS_GetEntryCount(S) CollCount (&(S)->Entries) |
117 | #endif |
118 | |
119 | void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index); |
120 | /* Insert the code entry at the index given. Following code entries will be |
121 | ** moved to slots with higher indices. |
122 | */ |
123 | |
124 | void CS_DelEntry (CodeSeg* S, unsigned Index); |
125 | /* Delete an entry from the code segment. This includes moving any associated |
126 | ** labels, removing references to labels and even removing the referenced labels |
127 | ** if the reference count drops to zero. |
128 | ** Note: Labels are moved forward if possible, that is, they are moved to the |
129 | ** next insn (not the preceeding one). |
130 | */ |
131 | |
132 | void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count); |
133 | /* Delete a range of code entries. This includes removing references to labels, |
134 | ** labels attached to the entries and so on. |
135 | */ |
136 | |
137 | void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos); |
138 | /* Move a range of entries from one position to another. Start is the index |
139 | ** of the first entry to move, Count is the number of entries and NewPos is |
140 | ** the index of the target entry. The entry with the index Start will later |
141 | ** have the index NewPos. All entries with indices NewPos and above are |
142 | ** moved to higher indices. If the code block is moved to the end of the |
143 | ** current code, and if pending labels exist, these labels will get attached |
144 | ** to the first instruction of the moved block (the first one after the |
145 | ** current code end) |
146 | */ |
147 | |
148 | #if defined(HAVE_INLINE) |
149 | INLINE void CS_MoveEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos) |
150 | /* Move an entry from one position to another. OldPos is the current position |
151 | ** of the entry, NewPos is the new position of the entry. |
152 | */ |
153 | { |
154 | CollMove (&S->Entries, OldPos, NewPos); |
155 | } |
156 | #else |
157 | # define CS_MoveEntry(S, OldPos, NewPos) CollMove (&(S)->Entries, OldPos, NewPos) |
158 | #endif |
159 | |
160 | #if defined(HAVE_INLINE) |
161 | INLINE struct CodeEntry* CS_GetEntry (CodeSeg* S, unsigned Index) |
162 | /* Get an entry from the given code segment */ |
163 | { |
164 | return CollAt (&S->Entries, Index); |
165 | } |
166 | #else |
167 | # define CS_GetEntry(S, Index) ((struct CodeEntry*) CollAt(&(S)->Entries, (Index))) |
168 | #endif |
169 | |
170 | struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index); |
171 | /* Get the code entry preceeding the one with the index Index. If there is no |
172 | ** preceeding code entry, return NULL. |
173 | */ |
174 | |
175 | struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index); |
176 | /* Get the code entry following the one with the index Index. If there is no |
177 | ** following code entry, return NULL. |
178 | */ |
179 | |
180 | int CS_GetEntries (CodeSeg* S, struct CodeEntry** List, |
181 | unsigned Start, unsigned Count); |
182 | /* Get Count code entries into List starting at index start. Return true if |
183 | ** we got the lines, return false if not enough lines were available. |
184 | */ |
185 | |
186 | unsigned CS_GetEntryIndex (CodeSeg* S, struct CodeEntry* E); |
187 | /* Return the index of a code entry */ |
188 | |
189 | int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count); |
190 | /* Return true if any of the code entries in the given range has a label |
191 | ** attached. If the code segment does not span the given range, check the |
192 | ** possible span instead. |
193 | */ |
194 | |
195 | #if defined(HAVE_INLINE) |
196 | INLINE int CS_HavePendingLabel (const CodeSeg* S) |
197 | /* Return true if there are open labels that will get attached to the next |
198 | ** instruction that is added. |
199 | */ |
200 | { |
201 | return (CollCount (&S->Labels) > 0); |
202 | } |
203 | #else |
204 | # define CS_HavePendingLabel(S) (CollCount (&(S)->Labels) > 0) |
205 | #endif |
206 | |
207 | CodeLabel* CS_AddLabel (CodeSeg* S, const char* Name); |
208 | /* Add a code label for the next instruction to follow */ |
209 | |
210 | CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E); |
211 | /* If the code entry E does already have a label, return it. Otherwise |
212 | ** create a new label, attach it to E and return it. |
213 | */ |
214 | |
215 | void CS_DelLabel (CodeSeg* S, CodeLabel* L); |
216 | /* Remove references from this label and delete it. */ |
217 | |
218 | void CS_MergeLabels (CodeSeg* S); |
219 | /* Merge code labels. That means: For each instruction, remove all labels but |
220 | ** one and adjust references accordingly. |
221 | */ |
222 | |
223 | void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New); |
224 | /* Move all labels from Old to New. The routine will move the labels itself |
225 | ** if New does not have any labels, and move references if there is at least |
226 | ** a label for new. If references are moved, the old label is deleted |
227 | ** afterwards. |
228 | */ |
229 | |
230 | void CS_RemoveLabelRef (CodeSeg* S, struct CodeEntry* E); |
231 | /* Remove the reference between E and the label it jumps to. The reference |
232 | ** will be removed on both sides and E->JumpTo will be 0 after that. If |
233 | ** the reference was the only one for the label, the label will get |
234 | ** deleted. |
235 | */ |
236 | |
237 | void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L); |
238 | /* Change the reference of E to L instead of the current one. If this |
239 | ** was the only reference to the old label, the old label will get |
240 | ** deleted. |
241 | */ |
242 | |
243 | void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last); |
244 | /* Delete all entries between first and last, both inclusive. The function |
245 | ** can only handle basic blocks (First is the only entry, Last the only exit) |
246 | ** and no open labels. It will call FAIL if any of these preconditions are |
247 | ** violated. |
248 | */ |
249 | |
250 | void CS_DelCodeAfter (CodeSeg* S, unsigned Last); |
251 | /* Delete all entries including the given one */ |
252 | |
253 | void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last); |
254 | /* Remove all user marks from the entries in the given range */ |
255 | |
256 | #if defined(HAVE_INLINE) |
257 | INLINE void CS_ResetAllMarks (CodeSeg* S) |
258 | /* Remove all user marks from the code segment */ |
259 | { |
260 | if (CS_GetEntryCount (S) > 0) { |
261 | CS_ResetMarks (S, 0, CS_GetEntryCount (S)); |
262 | } |
263 | } |
264 | #else |
265 | # define CS_ResetAllMarks(S) \ |
266 | ((CS_GetEntryCount (S) > 0)? CS_ResetMarks (S, 0, CS_GetEntryCount (S)) : (void) 0) |
267 | #endif |
268 | |
269 | int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last); |
270 | /* Check if the given code segment range is a basic block. That is, check if |
271 | ** First is the only entrance and Last is the only exit. This means that no |
272 | ** jump/branch inside the block may jump to an insn below First or after(!) |
273 | ** Last, and that no insn may jump into this block from the outside. |
274 | */ |
275 | |
276 | void CS_OutputPrologue (const CodeSeg* S); |
277 | /* If the given code segment is a code segment for a function, output the |
278 | ** assembler prologue into the file. That is: Output a comment header, switch |
279 | ** to the correct segment and enter the local function scope. If the code |
280 | ** segment is global, do nothing. |
281 | */ |
282 | |
283 | void CS_OutputEpilogue (const CodeSeg* S); |
284 | /* If the given code segment is a code segment for a function, output the |
285 | ** assembler epilogue into the file. That is: Close the local function scope. |
286 | */ |
287 | |
288 | void CS_Output (CodeSeg* S); |
289 | /* Output the code segment data to a file */ |
290 | |
291 | void CS_FreeRegInfo (CodeSeg* S); |
292 | /* Free register infos for all instructions */ |
293 | |
294 | void CS_GenRegInfo (CodeSeg* S); |
295 | /* Generate register infos for all instructions */ |
296 | |
297 | |
298 | |
299 | /* End of codeseg.h */ |
300 | |
301 | #endif |
302 | |