]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 A |
1 | # Copyright (C) 2011 Apple Inc. All rights reserved. |
2 | # | |
3 | # Redistribution and use in source and binary forms, with or without | |
4 | # modification, are permitted provided that the following conditions | |
5 | # are met: | |
6 | # 1. Redistributions of source code must retain the above copyright | |
7 | # notice, this list of conditions and the following disclaimer. | |
8 | # 2. Redistributions in binary form must reproduce the above copyright | |
9 | # notice, this list of conditions and the following disclaimer in the | |
10 | # documentation and/or other materials provided with the distribution. | |
11 | # | |
12 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
13 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
14 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
15 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
16 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
17 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
18 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
19 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
20 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
21 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
22 | # THE POSSIBILITY OF SUCH DAMAGE. | |
23 | ||
24 | require "ast" | |
25 | ||
26 | # | |
27 | # node.resolveSettings(settings) | |
28 | # | |
29 | # Construct a new AST that does not have any IfThenElse nodes by | |
30 | # substituting concrete boolean values for each Setting. | |
31 | # | |
32 | ||
33 | class Node | |
34 | def resolveSettings(settings) | |
35 | mapChildren { | |
36 | | child | | |
37 | child.resolveSettings(settings) | |
38 | } | |
39 | end | |
40 | end | |
41 | ||
42 | class True | |
43 | def resolveSettings(settings) | |
44 | self | |
45 | end | |
46 | end | |
47 | ||
48 | class False | |
49 | def resolveSettings(settings) | |
50 | self | |
51 | end | |
52 | end | |
53 | ||
54 | class Setting | |
55 | def resolveSettings(settings) | |
56 | settings[@name].asNode | |
57 | end | |
58 | end | |
59 | ||
60 | class And | |
61 | def resolveSettings(settings) | |
62 | (@left.resolveSettings(settings).value and @right.resolveSettings(settings).value).asNode | |
63 | end | |
64 | end | |
65 | ||
66 | class Or | |
67 | def resolveSettings(settings) | |
68 | (@left.resolveSettings(settings).value or @right.resolveSettings(settings).value).asNode | |
69 | end | |
70 | end | |
71 | ||
72 | class Not | |
73 | def resolveSettings(settings) | |
74 | (not @child.resolveSettings(settings).value).asNode | |
75 | end | |
76 | end | |
77 | ||
78 | class IfThenElse | |
79 | def resolveSettings(settings) | |
80 | if @predicate.resolveSettings(settings).value | |
81 | @thenCase.resolveSettings(settings) | |
82 | else | |
83 | @elseCase.resolveSettings(settings) | |
84 | end | |
85 | end | |
86 | end | |
87 | ||
88 | class Sequence | |
89 | def resolveSettings(settings) | |
90 | newList = [] | |
91 | @list.each { | |
92 | | item | | |
93 | item = item.resolveSettings(settings) | |
94 | if item.is_a? Sequence | |
95 | newList += item.list | |
96 | else | |
97 | newList << item | |
98 | end | |
99 | } | |
100 | Sequence.new(codeOrigin, newList) | |
101 | end | |
102 | end | |
103 | ||
104 | # | |
105 | # node.demacroify(macros) | |
106 | # node.substitute(mapping) | |
107 | # | |
108 | # demacroify() constructs a new AST that does not have any Macro | |
109 | # nodes, while substitute() replaces Variable nodes with the given | |
110 | # nodes in the mapping. | |
111 | # | |
112 | ||
113 | class Node | |
114 | def demacroify(macros) | |
115 | mapChildren { | |
116 | | child | | |
117 | child.demacroify(macros) | |
118 | } | |
119 | end | |
120 | ||
121 | def substitute(mapping) | |
122 | mapChildren { | |
123 | | child | | |
124 | child.substitute(mapping) | |
125 | } | |
126 | end | |
127 | ||
128 | def substituteLabels(mapping) | |
129 | mapChildren { | |
130 | | child | | |
131 | child.substituteLabels(mapping) | |
132 | } | |
133 | end | |
134 | end | |
135 | ||
136 | class Macro | |
137 | def substitute(mapping) | |
138 | myMapping = {} | |
139 | mapping.each_pair { | |
140 | | key, value | | |
141 | unless @variables.include? key | |
142 | myMapping[key] = value | |
143 | end | |
144 | } | |
145 | mapChildren { | |
146 | | child | | |
147 | child.substitute(myMapping) | |
148 | } | |
149 | end | |
150 | end | |
151 | ||
152 | class Variable | |
153 | def substitute(mapping) | |
154 | if mapping[self] | |
155 | mapping[self] | |
156 | else | |
157 | self | |
158 | end | |
159 | end | |
160 | end | |
161 | ||
162 | class LocalLabel | |
163 | def substituteLabels(mapping) | |
164 | if mapping[self] | |
165 | mapping[self] | |
166 | else | |
167 | self | |
168 | end | |
169 | end | |
170 | end | |
171 | ||
172 | class Sequence | |
173 | def substitute(constants) | |
174 | newList = [] | |
175 | myConstants = constants.dup | |
176 | @list.each { | |
177 | | item | | |
178 | if item.is_a? ConstDecl | |
179 | myConstants[item.variable] = item.value.substitute(myConstants) | |
180 | else | |
181 | newList << item.substitute(myConstants) | |
182 | end | |
183 | } | |
184 | Sequence.new(codeOrigin, newList) | |
185 | end | |
186 | ||
187 | def renameLabels(comment) | |
188 | mapping = {} | |
189 | ||
190 | @list.each { | |
191 | | item | | |
192 | if item.is_a? LocalLabel | |
193 | mapping[item] = LocalLabel.unique(if comment then comment + "_" else "" end + item.cleanName) | |
194 | end | |
195 | } | |
196 | ||
197 | substituteLabels(mapping) | |
198 | end | |
199 | ||
200 | def demacroify(macros) | |
201 | myMacros = macros.dup | |
202 | @list.each { | |
203 | | item | | |
204 | if item.is_a? Macro | |
205 | myMacros[item.name] = item | |
206 | end | |
207 | } | |
208 | newList = [] | |
209 | @list.each { | |
210 | | item | | |
211 | if item.is_a? Macro | |
212 | # Ignore. | |
213 | elsif item.is_a? MacroCall | |
214 | mapping = {} | |
215 | myMyMacros = myMacros.dup | |
216 | raise "Could not find macro #{item.name} at #{item.codeOriginString}" unless myMacros[item.name] | |
217 | raise "Argument count mismatch for call to #{item.name} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size | |
218 | item.operands.size.times { | |
219 | | idx | | |
220 | if item.operands[idx].is_a? Variable and myMacros[item.operands[idx].name] | |
221 | myMyMacros[myMacros[item.name].variables[idx].name] = myMacros[item.operands[idx].name] | |
222 | mapping[myMacros[item.name].variables[idx].name] = nil | |
223 | elsif item.operands[idx].is_a? Macro | |
224 | myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx] | |
225 | mapping[myMacros[item.name].variables[idx].name] = nil | |
226 | else | |
227 | myMyMacros[myMacros[item.name].variables[idx]] = nil | |
228 | mapping[myMacros[item.name].variables[idx]] = item.operands[idx] | |
229 | end | |
230 | } | |
231 | newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.name).list | |
232 | else | |
233 | newList << item.demacroify(myMacros) | |
234 | end | |
235 | } | |
236 | Sequence.new(codeOrigin, newList).substitute({}) | |
237 | end | |
238 | end | |
239 | ||
240 | # | |
241 | # node.resolveOffsets(offsets, sizes) | |
242 | # | |
243 | # Construct a new AST that has offset values instead of symbolic | |
244 | # offsets. | |
245 | # | |
246 | ||
247 | class Node | |
248 | def resolveOffsets(offsets, sizes) | |
249 | mapChildren { | |
250 | | child | | |
251 | child.resolveOffsets(offsets, sizes) | |
252 | } | |
253 | end | |
254 | end | |
255 | ||
256 | class StructOffset | |
257 | def resolveOffsets(offsets, sizes) | |
258 | if offsets[self] | |
259 | Immediate.new(codeOrigin, offsets[self]) | |
260 | else | |
261 | self | |
262 | end | |
263 | end | |
264 | end | |
265 | ||
266 | class Sizeof | |
267 | def resolveOffsets(offsets, sizes) | |
268 | if sizes[self] | |
269 | Immediate.new(codeOrigin, sizes[self]) | |
270 | else | |
271 | puts "Could not find #{self.inspect} in #{sizes.keys.inspect}" | |
272 | puts "sizes = #{sizes.inspect}" | |
273 | self | |
274 | end | |
275 | end | |
276 | end | |
277 | ||
278 | # | |
279 | # node.fold | |
280 | # | |
281 | # Resolve constant references and compute arithmetic expressions. | |
282 | # | |
283 | ||
284 | class Node | |
285 | def fold | |
286 | mapChildren { | |
287 | | child | | |
288 | child.fold | |
289 | } | |
290 | end | |
291 | end | |
292 | ||
293 | class AddImmediates | |
294 | def fold | |
295 | @left = @left.fold | |
296 | @right = @right.fold | |
297 | return self unless @left.is_a? Immediate | |
298 | return self unless @right.is_a? Immediate | |
299 | Immediate.new(codeOrigin, @left.value + @right.value) | |
300 | end | |
301 | end | |
302 | ||
303 | class SubImmediates | |
304 | def fold | |
305 | @left = @left.fold | |
306 | @right = @right.fold | |
307 | return self unless @left.is_a? Immediate | |
308 | return self unless @right.is_a? Immediate | |
309 | Immediate.new(codeOrigin, @left.value - @right.value) | |
310 | end | |
311 | end | |
312 | ||
313 | class MulImmediates | |
314 | def fold | |
315 | @left = @left.fold | |
316 | @right = @right.fold | |
317 | return self unless @left.is_a? Immediate | |
318 | return self unless @right.is_a? Immediate | |
319 | Immediate.new(codeOrigin, @left.value * @right.value) | |
320 | end | |
321 | end | |
322 | ||
323 | class NegImmediate | |
324 | def fold | |
325 | @child = @child.fold | |
326 | return self unless @child.is_a? Immediate | |
327 | Immediate.new(codeOrigin, -@child.value) | |
328 | end | |
329 | end | |
330 | ||
331 | class OrImmediates | |
332 | def fold | |
333 | @left = @left.fold | |
334 | @right = @right.fold | |
335 | return self unless @left.is_a? Immediate | |
336 | return self unless @right.is_a? Immediate | |
337 | Immediate.new(codeOrigin, @left.value | @right.value) | |
338 | end | |
339 | end | |
340 | ||
341 | class AndImmediates | |
342 | def fold | |
343 | @left = @left.fold | |
344 | @right = @right.fold | |
345 | return self unless @left.is_a? Immediate | |
346 | return self unless @right.is_a? Immediate | |
347 | Immediate.new(codeOrigin, @left.value & @right.value) | |
348 | end | |
349 | end | |
350 | ||
351 | class XorImmediates | |
352 | def fold | |
353 | @left = @left.fold | |
354 | @right = @right.fold | |
355 | return self unless @left.is_a? Immediate | |
356 | return self unless @right.is_a? Immediate | |
357 | Immediate.new(codeOrigin, @left.value ^ @right.value) | |
358 | end | |
359 | end | |
360 | ||
361 | class BitnotImmediate | |
362 | def fold | |
363 | @child = @child.fold | |
364 | return self unless @child.is_a? Immediate | |
365 | Immediate.new(codeOrigin, ~@child.value) | |
366 | end | |
367 | end | |
368 | ||
369 | # | |
370 | # node.resolveAfterSettings(offsets, sizes) | |
371 | # | |
372 | # Compile assembly against a set of offsets. | |
373 | # | |
374 | ||
375 | class Node | |
376 | def resolve(offsets, sizes) | |
377 | demacroify({}).resolveOffsets(offsets, sizes).fold | |
378 | end | |
379 | end | |
380 | ||
381 | # | |
382 | # node.validate | |
383 | # | |
384 | # Checks that the node is ready for backend compilation. | |
385 | # | |
386 | ||
387 | class Node | |
388 | def validate | |
389 | raise "Unresolved #{dump} at #{codeOriginString}" | |
390 | end | |
391 | ||
392 | def validateChildren | |
393 | children.each { | |
394 | | node | | |
395 | node.validate | |
396 | } | |
397 | end | |
398 | end | |
399 | ||
400 | class Sequence | |
401 | def validate | |
402 | validateChildren | |
403 | end | |
404 | end | |
405 | ||
406 | class Immediate | |
407 | def validate | |
408 | end | |
409 | end | |
410 | ||
411 | class RegisterID | |
412 | def validate | |
413 | end | |
414 | end | |
415 | ||
416 | class FPRegisterID | |
417 | def validate | |
418 | end | |
419 | end | |
420 | ||
421 | class Address | |
422 | def validate | |
423 | validateChildren | |
424 | end | |
425 | end | |
426 | ||
427 | class BaseIndex | |
428 | def validate | |
429 | validateChildren | |
430 | end | |
431 | end | |
432 | ||
433 | class AbsoluteAddress | |
434 | def validate | |
435 | validateChildren | |
436 | end | |
437 | end | |
438 | ||
439 | class Instruction | |
440 | def validate | |
441 | validateChildren | |
442 | end | |
443 | end | |
444 | ||
445 | class Error | |
446 | def validate | |
447 | end | |
448 | end | |
449 | ||
450 | class Label | |
451 | def validate | |
452 | end | |
453 | end | |
454 | ||
455 | class LocalLabel | |
456 | def validate | |
457 | end | |
458 | end | |
459 | ||
460 | class LabelReference | |
461 | def validate | |
462 | end | |
463 | end | |
464 | ||
465 | class LocalLabelReference | |
466 | def validate | |
467 | end | |
468 | end | |
469 | ||
470 | class Skip | |
471 | def validate | |
472 | end | |
473 | end | |
474 |