fourthTier: We should have a reduced FTL LLVM pipeline tool in the repository
[WebKit-https.git] / Tools / ReducedFTL / combineModules.rb
1 #!/usr/bin/env ruby
2
3 # Copyright (C) 2013 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 #    notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 #    notice, this list of conditions and the following disclaimer in the
12 #    documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 # THE POSSIBILITY OF SUCH DAMAGE.
25
26 class Reference
27     attr_reader :kind, :number
28     
29     def initialize(kind, number)
30         @kind = kind
31         @number = number
32     end
33     
34     def resolve(hashTable, bangTable)
35         case @kind
36         when "#"
37             result = hashTable[@number]
38         when "!"
39             result = bangTable[@number]
40         else
41             raise
42         end
43         raise unless result
44         result
45     end
46 end
47
48 def parse(string)
49     result = []
50     until string.empty?
51         before, match, string = string.partition(/[!#]([0-9]+)/)
52         result << before
53         if match.empty?
54             result << string
55             break
56         end
57         result << Reference.new(match[0..0], match[1..-1].to_i)
58     end
59     result
60 end
61
62 class MetaData
63     attr_reader :index, :name, :parent
64     
65     def initialize(index, name, parent)
66         @index = index
67         @name = name
68         @parent = parent
69     end
70 end
71
72 $definitions = []
73 $declarations = {}
74 $attributes = []
75 $metaData = {}
76 $attributesBackMap = {}
77 $count = 0
78
79 loop {
80     line = $stdin.readline
81     break if line =~ /^define/
82 }
83
84 # Loop over all definitions.
85 shouldContinue = true
86 while shouldContinue
87     # We're starting a new definition.
88     body = ""
89     loop {
90         line = $stdin.readline
91         break if line.chomp == "}"
92         body += line
93     }
94     
95     body = parse(body)
96     
97     declarations=[]
98     metaDataMap=[]
99     attributeMap = []
100     unresolvedMetaData = []
101     
102     loop {
103         line = $stdin.gets
104         
105         if not line
106             shouldContinue = false
107             break
108         elsif line =~ /^define/
109             break
110         elsif line =~ /^declare/
111             declarations << parse(line)
112         elsif line =~ /!([0-9]+) = metadata !{metadata !\"([a-zA-Z0-9_]+)\"}/
113             index = $1.to_i
114             name = $2
115             unless $metaData[name]
116                 $metaData[name] = MetaData.new($metaData.size, name, nil)
117             end
118             metaDataMap[index] = $metaData[$2].index
119         elsif line =~ /!([0-9]+) = metadata !{metadata !\"([a-zA-Z0-9_]+)\", metadata !([0-9]+)/
120             metaData = MetaData.new($1.to_i, $2, $3.to_i)
121             unresolvedMetaData << metaData
122         elsif line =~ /attributes #([0-9]+) = /
123             attributeNumber = $1.to_i
124             attributeBody = $~.post_match
125             if $attributesBackMap[attributeBody]
126                 attributeMap[attributeNumber] = $attributesBackMap[attributeBody]
127             else
128                 attributeMap[attributeNumber] = $attributes.size
129                 $attributesBackMap[attributeBody] = $attributes.size
130                 $attributes << attributeBody
131             end
132         end
133     }
134     
135     # Iteratively resolve meta-data references
136     until unresolvedMetaData.empty?
137         index = 0
138         while index < unresolvedMetaData.size
139             metaData = unresolvedMetaData[index]
140             if $metaData[metaData.name]
141                 metaDataMap[metaData.index] = $metaData[metaData.name].index
142                 unresolvedMetaData[index] = unresolvedMetaData[-1]
143                 unresolvedMetaData.pop
144             elsif metaDataMap[metaData.parent]
145                 metaDataMap[metaData.index] = $metaData.size
146                 $metaData[metaData.name] = MetaData.new($metaData.size, metaData.name, metaDataMap[metaData.parent])
147                 unresolvedMetaData[index] = unresolvedMetaData[-1]
148                 unresolvedMetaData.pop
149             else
150                 index += 1
151             end
152         end
153     end
154     
155     # Output the body with all of the things remapped.
156     puts "define i64 @jsBody_#{$count += 1}(i64) {"
157     body.each {
158         | thing |
159         if thing.is_a? Reference
160             print(thing.kind + thing.resolve(attributeMap, metaDataMap).to_s)
161         else
162             print(thing)
163         end
164     }
165     puts "}"
166     
167     # Figure out what to do with declarations.
168     declarations.each {
169         | declaration |
170         declaration = declaration.map {
171             | thing |
172             if thing.is_a? Reference
173                 thing.kind + thing.resolve(attributeMap, metaDataMap).to_s
174             else
175                 thing
176             end
177         }
178         declaration = declaration.join('')
179         
180         next if $declarations[declaration]
181         
182         $declarations[declaration] = true
183     }
184 end
185
186 $declarations.each_key {
187     | declaration |
188     puts declaration
189 }
190
191 $attributes.each_with_index {
192     | attribute, index |
193     puts "attributes ##{index} = #{attribute}"
194 }
195
196 $metaData.each_value {
197     | metaData |
198     print "!#{metaData.index} = metadata !{metadata !\"#{metaData.name}\""
199     if metaData.parent
200         print ", metadata !#{metaData.parent}"
201     end
202     puts "}"
203 }
204