fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 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 | |
commit-queue@webkit.org | 782c20b | 2012-07-14 00:44:47 +0000 | [diff] [blame] | 24 | require "config" |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 25 | require "ast" |
| 26 | |
| 27 | # |
| 28 | # node.resolveSettings(settings) |
| 29 | # |
| 30 | # Construct a new AST that does not have any IfThenElse nodes by |
| 31 | # substituting concrete boolean values for each Setting. |
| 32 | # |
| 33 | |
| 34 | class Node |
| 35 | def resolveSettings(settings) |
| 36 | mapChildren { |
| 37 | | child | |
| 38 | child.resolveSettings(settings) |
| 39 | } |
| 40 | end |
| 41 | end |
| 42 | |
| 43 | class True |
| 44 | def resolveSettings(settings) |
| 45 | self |
| 46 | end |
| 47 | end |
| 48 | |
| 49 | class False |
| 50 | def resolveSettings(settings) |
| 51 | self |
| 52 | end |
| 53 | end |
| 54 | |
| 55 | class Setting |
| 56 | def resolveSettings(settings) |
| 57 | settings[@name].asNode |
| 58 | end |
| 59 | end |
| 60 | |
| 61 | class And |
| 62 | def resolveSettings(settings) |
| 63 | (@left.resolveSettings(settings).value and @right.resolveSettings(settings).value).asNode |
| 64 | end |
| 65 | end |
| 66 | |
| 67 | class Or |
| 68 | def resolveSettings(settings) |
| 69 | (@left.resolveSettings(settings).value or @right.resolveSettings(settings).value).asNode |
| 70 | end |
| 71 | end |
| 72 | |
| 73 | class Not |
| 74 | def resolveSettings(settings) |
| 75 | (not @child.resolveSettings(settings).value).asNode |
| 76 | end |
| 77 | end |
| 78 | |
| 79 | class IfThenElse |
| 80 | def resolveSettings(settings) |
| 81 | if @predicate.resolveSettings(settings).value |
| 82 | @thenCase.resolveSettings(settings) |
| 83 | else |
| 84 | @elseCase.resolveSettings(settings) |
| 85 | end |
| 86 | end |
| 87 | end |
| 88 | |
| 89 | class Sequence |
| 90 | def resolveSettings(settings) |
| 91 | newList = [] |
| 92 | @list.each { |
| 93 | | item | |
| 94 | item = item.resolveSettings(settings) |
| 95 | if item.is_a? Sequence |
| 96 | newList += item.list |
| 97 | else |
| 98 | newList << item |
| 99 | end |
| 100 | } |
| 101 | Sequence.new(codeOrigin, newList) |
| 102 | end |
| 103 | end |
| 104 | |
| 105 | # |
| 106 | # node.demacroify(macros) |
| 107 | # node.substitute(mapping) |
| 108 | # |
| 109 | # demacroify() constructs a new AST that does not have any Macro |
| 110 | # nodes, while substitute() replaces Variable nodes with the given |
| 111 | # nodes in the mapping. |
| 112 | # |
| 113 | |
| 114 | class Node |
| 115 | def demacroify(macros) |
| 116 | mapChildren { |
| 117 | | child | |
| 118 | child.demacroify(macros) |
| 119 | } |
| 120 | end |
| 121 | |
| 122 | def substitute(mapping) |
| 123 | mapChildren { |
| 124 | | child | |
| 125 | child.substitute(mapping) |
| 126 | } |
| 127 | end |
| 128 | |
| 129 | def substituteLabels(mapping) |
| 130 | mapChildren { |
| 131 | | child | |
| 132 | child.substituteLabels(mapping) |
| 133 | } |
| 134 | end |
| 135 | end |
| 136 | |
| 137 | class Macro |
| 138 | def substitute(mapping) |
| 139 | myMapping = {} |
| 140 | mapping.each_pair { |
| 141 | | key, value | |
| 142 | unless @variables.include? key |
| 143 | myMapping[key] = value |
| 144 | end |
| 145 | } |
| 146 | mapChildren { |
| 147 | | child | |
| 148 | child.substitute(myMapping) |
| 149 | } |
| 150 | end |
| 151 | end |
| 152 | |
| 153 | class Variable |
| 154 | def substitute(mapping) |
| 155 | if mapping[self] |
| 156 | mapping[self] |
| 157 | else |
| 158 | self |
| 159 | end |
| 160 | end |
| 161 | end |
| 162 | |
| 163 | class LocalLabel |
| 164 | def substituteLabels(mapping) |
| 165 | if mapping[self] |
| 166 | mapping[self] |
| 167 | else |
| 168 | self |
| 169 | end |
| 170 | end |
| 171 | end |
| 172 | |
| 173 | class Sequence |
| 174 | def substitute(constants) |
| 175 | newList = [] |
| 176 | myConstants = constants.dup |
| 177 | @list.each { |
| 178 | | item | |
| 179 | if item.is_a? ConstDecl |
| 180 | myConstants[item.variable] = item.value.substitute(myConstants) |
| 181 | else |
| 182 | newList << item.substitute(myConstants) |
| 183 | end |
| 184 | } |
| 185 | Sequence.new(codeOrigin, newList) |
| 186 | end |
| 187 | |
| 188 | def renameLabels(comment) |
| 189 | mapping = {} |
| 190 | |
| 191 | @list.each { |
| 192 | | item | |
| 193 | if item.is_a? LocalLabel |
| 194 | mapping[item] = LocalLabel.unique(if comment then comment + "_" else "" end + item.cleanName) |
| 195 | end |
| 196 | } |
| 197 | |
| 198 | substituteLabels(mapping) |
| 199 | end |
| 200 | |
| 201 | def demacroify(macros) |
| 202 | myMacros = macros.dup |
| 203 | @list.each { |
| 204 | | item | |
| 205 | if item.is_a? Macro |
| 206 | myMacros[item.name] = item |
| 207 | end |
| 208 | } |
| 209 | newList = [] |
| 210 | @list.each { |
| 211 | | item | |
| 212 | if item.is_a? Macro |
| 213 | # Ignore. |
| 214 | elsif item.is_a? MacroCall |
| 215 | mapping = {} |
| 216 | myMyMacros = myMacros.dup |
| 217 | raise "Could not find macro #{item.name} at #{item.codeOriginString}" unless myMacros[item.name] |
| 218 | raise "Argument count mismatch for call to #{item.name} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size |
| 219 | item.operands.size.times { |
| 220 | | idx | |
| 221 | if item.operands[idx].is_a? Variable and myMacros[item.operands[idx].name] |
| 222 | myMyMacros[myMacros[item.name].variables[idx].name] = myMacros[item.operands[idx].name] |
| 223 | mapping[myMacros[item.name].variables[idx].name] = nil |
| 224 | elsif item.operands[idx].is_a? Macro |
| 225 | myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx] |
| 226 | mapping[myMacros[item.name].variables[idx].name] = nil |
| 227 | else |
| 228 | myMyMacros[myMacros[item.name].variables[idx]] = nil |
| 229 | mapping[myMacros[item.name].variables[idx]] = item.operands[idx] |
| 230 | end |
| 231 | } |
commit-queue@webkit.org | e602eca | 2012-07-19 20:53:22 +0000 | [diff] [blame] | 232 | if item.annotation |
| 233 | newList << Instruction.new(item.codeOrigin, "localAnnotation", [], item.annotation) |
| 234 | end |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 235 | newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.name).list |
| 236 | else |
| 237 | newList << item.demacroify(myMacros) |
| 238 | end |
| 239 | } |
| 240 | Sequence.new(codeOrigin, newList).substitute({}) |
| 241 | end |
| 242 | end |
| 243 | |
| 244 | # |
| 245 | # node.resolveOffsets(offsets, sizes) |
| 246 | # |
| 247 | # Construct a new AST that has offset values instead of symbolic |
| 248 | # offsets. |
| 249 | # |
| 250 | |
| 251 | class Node |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 252 | def resolveOffsets(constantsMap) |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 253 | mapChildren { |
| 254 | | child | |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 255 | child.resolveOffsets(constantsMap) |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 256 | } |
| 257 | end |
| 258 | end |
| 259 | |
| 260 | class StructOffset |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 261 | def resolveOffsets(constantsMap) |
| 262 | if constantsMap[self] |
| 263 | Immediate.new(codeOrigin, constantsMap[self]) |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 264 | else |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 265 | puts "Could not find #{self.inspect} in #{constantsMap.keys.inspect}" |
| 266 | puts "sizes = #{constantsMap.inspect}" |
| 267 | raise |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 268 | end |
| 269 | end |
| 270 | end |
| 271 | |
| 272 | class Sizeof |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 273 | def resolveOffsets(constantsMap) |
| 274 | if constantsMap[self] |
| 275 | Immediate.new(codeOrigin, constantsMap[self]) |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 276 | else |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 277 | puts "Could not find #{self.inspect} in #{constantsMap.keys.inspect}" |
| 278 | puts "sizes = #{constantsMap.inspect}" |
| 279 | raise |
| 280 | end |
| 281 | end |
| 282 | end |
| 283 | |
| 284 | class ConstExpr |
| 285 | def resolveOffsets(constantsMap) |
| 286 | if constantsMap[self] |
| 287 | Immediate.new(codeOrigin, constantsMap[self]) |
| 288 | else |
| 289 | puts "Could not find #{self.inspect} in #{constantsMap.keys.inspect}" |
| 290 | puts "sizes = #{constantsMap.inspect}" |
| 291 | raise |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 292 | end |
| 293 | end |
| 294 | end |
| 295 | |
| 296 | # |
| 297 | # node.fold |
| 298 | # |
| 299 | # Resolve constant references and compute arithmetic expressions. |
| 300 | # |
| 301 | |
| 302 | class Node |
| 303 | def fold |
| 304 | mapChildren { |
| 305 | | child | |
| 306 | child.fold |
| 307 | } |
| 308 | end |
| 309 | end |
| 310 | |
| 311 | class AddImmediates |
| 312 | def fold |
| 313 | @left = @left.fold |
| 314 | @right = @right.fold |
fpizlo@apple.com | bd60cf6 | 2017-09-27 05:05:27 +0000 | [diff] [blame] | 315 | |
| 316 | return right.plusOffset(@left.value) if @left.is_a? Immediate and @right.is_a? LabelReference |
| 317 | return left.plusOffset(@right.value) if @left.is_a? LabelReference and @right.is_a? Immediate |
| 318 | |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 319 | return self unless @left.is_a? Immediate |
| 320 | return self unless @right.is_a? Immediate |
| 321 | Immediate.new(codeOrigin, @left.value + @right.value) |
| 322 | end |
| 323 | end |
| 324 | |
| 325 | class SubImmediates |
| 326 | def fold |
| 327 | @left = @left.fold |
| 328 | @right = @right.fold |
fpizlo@apple.com | bd60cf6 | 2017-09-27 05:05:27 +0000 | [diff] [blame] | 329 | |
| 330 | return left.plusOffset(-@right.value) if @left.is_a? LabelReference and @right.is_a? Immediate |
| 331 | |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 332 | return self unless @left.is_a? Immediate |
| 333 | return self unless @right.is_a? Immediate |
| 334 | Immediate.new(codeOrigin, @left.value - @right.value) |
| 335 | end |
| 336 | end |
| 337 | |
| 338 | class MulImmediates |
| 339 | def fold |
| 340 | @left = @left.fold |
| 341 | @right = @right.fold |
| 342 | return self unless @left.is_a? Immediate |
| 343 | return self unless @right.is_a? Immediate |
| 344 | Immediate.new(codeOrigin, @left.value * @right.value) |
| 345 | end |
| 346 | end |
| 347 | |
| 348 | class NegImmediate |
| 349 | def fold |
| 350 | @child = @child.fold |
| 351 | return self unless @child.is_a? Immediate |
| 352 | Immediate.new(codeOrigin, -@child.value) |
| 353 | end |
| 354 | end |
| 355 | |
fpizlo@apple.com | 685a420 | 2012-03-11 00:33:20 +0000 | [diff] [blame] | 356 | class OrImmediates |
| 357 | def fold |
| 358 | @left = @left.fold |
| 359 | @right = @right.fold |
| 360 | return self unless @left.is_a? Immediate |
| 361 | return self unless @right.is_a? Immediate |
| 362 | Immediate.new(codeOrigin, @left.value | @right.value) |
| 363 | end |
| 364 | end |
| 365 | |
| 366 | class AndImmediates |
| 367 | def fold |
| 368 | @left = @left.fold |
| 369 | @right = @right.fold |
| 370 | return self unless @left.is_a? Immediate |
| 371 | return self unless @right.is_a? Immediate |
| 372 | Immediate.new(codeOrigin, @left.value & @right.value) |
| 373 | end |
| 374 | end |
| 375 | |
| 376 | class XorImmediates |
| 377 | def fold |
| 378 | @left = @left.fold |
| 379 | @right = @right.fold |
| 380 | return self unless @left.is_a? Immediate |
| 381 | return self unless @right.is_a? Immediate |
| 382 | Immediate.new(codeOrigin, @left.value ^ @right.value) |
| 383 | end |
| 384 | end |
| 385 | |
| 386 | class BitnotImmediate |
| 387 | def fold |
| 388 | @child = @child.fold |
| 389 | return self unless @child.is_a? Immediate |
| 390 | Immediate.new(codeOrigin, ~@child.value) |
| 391 | end |
| 392 | end |
| 393 | |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 394 | # |
| 395 | # node.resolveAfterSettings(offsets, sizes) |
| 396 | # |
| 397 | # Compile assembly against a set of offsets. |
| 398 | # |
| 399 | |
| 400 | class Node |
keith_miller@apple.com | 628e2ca | 2017-07-30 03:01:12 +0000 | [diff] [blame] | 401 | def resolve(constantsMap) |
| 402 | demacroify({}).resolveOffsets(constantsMap).fold |
fpizlo@apple.com | 7bbcaab | 2012-02-22 05:23:19 +0000 | [diff] [blame] | 403 | end |
| 404 | end |
| 405 | |
fpizlo@apple.com | 685a420 | 2012-03-11 00:33:20 +0000 | [diff] [blame] | 406 | # |
| 407 | # node.validate |
| 408 | # |
| 409 | # Checks that the node is ready for backend compilation. |
| 410 | # |
| 411 | |
| 412 | class Node |
| 413 | def validate |
| 414 | raise "Unresolved #{dump} at #{codeOriginString}" |
| 415 | end |
| 416 | |
| 417 | def validateChildren |
| 418 | children.each { |
| 419 | | node | |
| 420 | node.validate |
| 421 | } |
| 422 | end |
| 423 | end |
| 424 | |
| 425 | class Sequence |
| 426 | def validate |
| 427 | validateChildren |
dbates@webkit.org | 98f0de0 | 2013-10-15 22:16:39 +0000 | [diff] [blame] | 428 | |
| 429 | # Further verify that this list contains only instructions, labels, and skips. |
| 430 | @list.each { |
| 431 | | node | |
| 432 | unless node.is_a? Instruction or |
| 433 | node.is_a? Label or |
| 434 | node.is_a? LocalLabel or |
| 435 | node.is_a? Skip |
| 436 | raise "Unexpected #{node.inspect} at #{node.codeOrigin}" |
| 437 | end |
| 438 | } |
fpizlo@apple.com | 685a420 | 2012-03-11 00:33:20 +0000 | [diff] [blame] | 439 | end |
| 440 | end |
| 441 | |
| 442 | class Immediate |
| 443 | def validate |
| 444 | end |
| 445 | end |
| 446 | |
msaboff@apple.com | 2935ca8 | 2014-08-12 03:20:04 +0000 | [diff] [blame] | 447 | class StringLiteral |
| 448 | def validate |
| 449 | end |
| 450 | end |
| 451 | |
fpizlo@apple.com | 685a420 | 2012-03-11 00:33:20 +0000 | [diff] [blame] | 452 | class RegisterID |
| 453 | def validate |
| 454 | end |
| 455 | end |
| 456 | |
| 457 | class FPRegisterID |
| 458 | def validate |
| 459 | end |
| 460 | end |
| 461 | |
| 462 | class Address |
| 463 | def validate |
| 464 | validateChildren |
| 465 | end |
| 466 | end |
| 467 | |
| 468 | class BaseIndex |
| 469 | def validate |
| 470 | validateChildren |
| 471 | end |
| 472 | end |
| 473 | |
| 474 | class AbsoluteAddress |
| 475 | def validate |
| 476 | validateChildren |
| 477 | end |
| 478 | end |
| 479 | |
| 480 | class Instruction |
| 481 | def validate |
| 482 | validateChildren |
| 483 | end |
| 484 | end |
| 485 | |
msaboff@apple.com | 8f8907e | 2014-04-10 22:33:59 +0000 | [diff] [blame] | 486 | class SubImmediates |
| 487 | def validate |
| 488 | raise "Invalid operand #{left.dump} to immediate subtraction" unless left.immediateOperand? |
| 489 | raise "Invalid operand #{right.dump} to immediate subtraction" unless right.immediateOperand? |
| 490 | end |
| 491 | end |
| 492 | |
fpizlo@apple.com | 685a420 | 2012-03-11 00:33:20 +0000 | [diff] [blame] | 493 | class Error |
| 494 | def validate |
| 495 | end |
| 496 | end |
| 497 | |
| 498 | class Label |
| 499 | def validate |
| 500 | end |
| 501 | end |
| 502 | |
| 503 | class LocalLabel |
| 504 | def validate |
| 505 | end |
| 506 | end |
| 507 | |
| 508 | class LabelReference |
| 509 | def validate |
| 510 | end |
| 511 | end |
| 512 | |
| 513 | class LocalLabelReference |
| 514 | def validate |
| 515 | end |
| 516 | end |
| 517 | |
| 518 | class Skip |
| 519 | def validate |
| 520 | end |
| 521 | end |
| 522 | |