|  | # Copyright (C) 2011-2020 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 "arm" | 
|  | require "arm64" | 
|  | require "ast" | 
|  | require "x86" | 
|  | require "mips" | 
|  | require "cloop" | 
|  |  | 
|  | begin | 
|  | require "arm64e" | 
|  | rescue LoadError | 
|  | end | 
|  |  | 
|  | BACKENDS = | 
|  | [ | 
|  | "X86", | 
|  | "X86_WIN", | 
|  | "X86_64", | 
|  | "X86_64_WIN", | 
|  | "ARMv7", | 
|  | "ARM64", | 
|  | "ARM64E", | 
|  | "MIPS", | 
|  | "C_LOOP", | 
|  | "C_LOOP_WIN" | 
|  | ] | 
|  |  | 
|  | # Keep the set of working backends separate from the set of backends that might be | 
|  | # supported. This is great because the BACKENDS list is almost like a reserved | 
|  | # words list, in that it causes settings resolution to treat those words specially. | 
|  | # Hence this lets us set aside the name of a backend we might want to support in | 
|  | # the future while not actually supporting the backend yet. | 
|  | WORKING_BACKENDS = | 
|  | [ | 
|  | "X86", | 
|  | "X86_WIN", | 
|  | "X86_64", | 
|  | "X86_64_WIN", | 
|  | "ARMv7", | 
|  | "ARM64", | 
|  | "ARM64E", | 
|  | "MIPS", | 
|  | "C_LOOP", | 
|  | "C_LOOP_WIN" | 
|  | ] | 
|  |  | 
|  | BACKEND_PATTERN = Regexp.new('\\A(' + BACKENDS.join(')|(') + ')\\Z') | 
|  |  | 
|  | $allBackends = {} | 
|  | $validBackends = {} | 
|  | BACKENDS.each { | 
|  | | backend | | 
|  | $validBackends[backend] = true | 
|  | $allBackends[backend] = true | 
|  | } | 
|  |  | 
|  | def canonicalizeBackendNames(backendNames) | 
|  | newBackendNames = [] | 
|  | backendNames.each { | 
|  | | backendName | | 
|  | backendName = backendName.upcase | 
|  | if backendName =~ /ARM.*/ | 
|  | backendName.sub!(/ARMV7([KS]?)(.*)/) { | _ | 'ARMv7' + $1.downcase + $2 } | 
|  | backendName = "ARM64" if backendName == "ARM64_32" | 
|  | end | 
|  | backendName = "X86" if backendName == "I386" | 
|  | newBackendNames << backendName | 
|  | newBackendNames << "ARMv7" if backendName.start_with?("ARMv7") | 
|  | } | 
|  | newBackendNames.uniq | 
|  | end | 
|  |  | 
|  | def includeOnlyBackends(list) | 
|  | newValidBackends = {} | 
|  | list.each { | 
|  | | backend | | 
|  | if $validBackends[backend] | 
|  | newValidBackends[backend] = true | 
|  | end | 
|  | } | 
|  | $validBackends = newValidBackends | 
|  | end | 
|  |  | 
|  | def isBackend?(backend) | 
|  | $allBackends[backend] | 
|  | end | 
|  |  | 
|  | def isValidBackend?(backend) | 
|  | $validBackends[backend] | 
|  | end | 
|  |  | 
|  | def validBackends | 
|  | $validBackends.keys | 
|  | end | 
|  |  | 
|  | class LoweringError < StandardError | 
|  | attr_reader :originString | 
|  |  | 
|  | def initialize(e, originString) | 
|  | super "#{e} (due to #{originString})" | 
|  | @originString = originString | 
|  | set_backtrace e.backtrace | 
|  | end | 
|  | end | 
|  |  | 
|  | class Node | 
|  | def lower(name) | 
|  | begin | 
|  | $activeBackend = name | 
|  | send("prepareToLower", name) | 
|  | send("lower#{name}") | 
|  | rescue => e | 
|  | raise LoweringError.new(e, codeOriginString) | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | # Overrides for lower() for those nodes that are backend-agnostic | 
|  |  | 
|  | class Label | 
|  | def lower(name) | 
|  | $asm.debugAnnotation codeOrigin.debugDirective if $enableDebugAnnotations | 
|  | $asm.putsLabel(self.name[1..-1], @global) | 
|  | end | 
|  | end | 
|  |  | 
|  | class LocalLabel | 
|  | def lower(name) | 
|  | $asm.putsLocalLabel "_offlineasm_#{self.name[1..-1]}" | 
|  | end | 
|  | end | 
|  |  | 
|  | class LabelReference | 
|  | def asmLabel | 
|  | if extern? | 
|  | Assembler.externLabelReference(name[1..-1]) | 
|  | else | 
|  | Assembler.labelReference(name[1..-1]) | 
|  | end | 
|  | end | 
|  |  | 
|  | def cLabel | 
|  | Assembler.cLabelReference(name[1..-1]) | 
|  | end | 
|  | end | 
|  |  | 
|  | class LocalLabelReference | 
|  | def asmLabel | 
|  | Assembler.localLabelReference("_offlineasm_"+name[1..-1]) | 
|  | end | 
|  |  | 
|  | def cLabel | 
|  | Assembler.cLocalLabelReference("_offlineasm_"+name[1..-1]) | 
|  | end | 
|  | end | 
|  |  | 
|  | class Skip | 
|  | def lower(name) | 
|  | end | 
|  | end | 
|  |  | 
|  | class Sequence | 
|  | def lower(name) | 
|  | $activeBackend = name | 
|  | if respond_to? "getModifiedList#{name}" | 
|  | newList = send("getModifiedList#{name}") | 
|  | newList.each { | 
|  | | node | | 
|  | node.lower(name) | 
|  | } | 
|  | elsif respond_to? "lower#{name}" | 
|  | send("lower#{name}") | 
|  | else | 
|  | @list.each { | 
|  | | node | | 
|  | node.lower(name) | 
|  | } | 
|  | end | 
|  | end | 
|  | end | 
|  |  |