| # 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 |
| |