| # Copyright (C) 2011 Apple Inc. All rights reserved. | 
 | # | 
 | # Redistribution and use in source and binary forms, with or without | 
 | # modification, are permitted provided that the following conditions | 
 | # are met: | 
 | # 1. Redistributions of source code must retain the above copyright | 
 | #    notice, this list of conditions and the following disclaimer. | 
 | # 2. Redistributions in binary form must reproduce the above copyright | 
 | #    notice, this list of conditions and the following disclaimer in the | 
 | #    documentation and/or other materials provided with the distribution. | 
 | # | 
 | # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | 
 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 
 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | 
 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 
 | # THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | require "config" | 
 | require "ast" | 
 |  | 
 | # | 
 | # "Optimization" passes. These are used to lower the representation for | 
 | # backends that cannot handle some of our higher-level instructions. | 
 | # | 
 |  | 
 | # | 
 | # A temporary - a variable that will be allocated to a register after we're | 
 | # done. | 
 | # | 
 |  | 
 | class Node | 
 |     def replaceTemporariesWithRegisters(kind) | 
 |         mapChildren { | 
 |             | node | | 
 |             node.replaceTemporariesWithRegisters(kind) | 
 |         } | 
 |     end | 
 | end | 
 |  | 
 | class Tmp < NoChildren | 
 |     attr_reader :firstMention, :lastMention | 
 |     attr_reader :kind | 
 |     attr_accessor :register | 
 |  | 
 |     def initialize(codeOrigin, kind) | 
 |         super(codeOrigin) | 
 |         @kind = kind | 
 |     end | 
 |      | 
 |     def dump | 
 |         "$tmp#{object_id}" | 
 |     end | 
 |      | 
 |     def mention!(position) | 
 |         if not @firstMention or position < @firstMention | 
 |             @firstMention = position | 
 |         end | 
 |         if not @lastMention or position > @lastMention | 
 |             @lastMention = position | 
 |         end | 
 |     end | 
 |      | 
 |     def replaceTemporariesWithRegisters(kind) | 
 |         if @kind == kind | 
 |             raise "Did not allocate register to temporary at #{codeOriginString}" unless @register | 
 |             @register | 
 |         else | 
 |             self | 
 |         end | 
 |     end | 
 |      | 
 |     def address? | 
 |         false | 
 |     end | 
 |      | 
 |     def label? | 
 |         false | 
 |     end | 
 |      | 
 |     def immediate? | 
 |         false | 
 |     end | 
 |      | 
 |     def register? | 
 |         true | 
 |     end | 
 | end | 
 |  | 
 | # Assign registers to temporaries, by finding which temporaries interfere | 
 | # with each other. Note that this relies on temporary live ranges not crossing | 
 | # basic block boundaries. | 
 |  | 
 | def assignRegistersToTemporaries(list, kind, registers) | 
 |     list.each_with_index { | 
 |         | node, index | | 
 |         node.filter(Tmp).uniq.each { | 
 |             | tmp | | 
 |             if tmp.kind == kind | 
 |                 tmp.mention! index | 
 |             end | 
 |         } | 
 |     } | 
 |      | 
 |     freeRegisters = registers.dup | 
 |     list.each_with_index { | 
 |         | node, index | | 
 |         tmpList = node.filter(Tmp).uniq | 
 |         tmpList.each { | 
 |             | tmp | | 
 |             if tmp.kind == kind and tmp.firstMention == index | 
 |                 raise "Could not allocate register to temporary at #{node.codeOriginString}" if freeRegisters.empty? | 
 |                 tmp.register = freeRegisters.pop | 
 |             end | 
 |         } | 
 |         tmpList.each { | 
 |             | tmp | | 
 |             if tmp.kind == kind and tmp.lastMention == index | 
 |                 freeRegisters.push tmp.register | 
 |                 raise "Register allocation inconsistency at #{node.codeOriginString}" if freeRegisters.size > registers.size | 
 |             end | 
 |         } | 
 |     } | 
 |      | 
 |     list.map { | 
 |         | node | | 
 |         node.replaceTemporariesWithRegisters(kind) | 
 |     } | 
 | end | 
 |  |