# 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