-
Notifications
You must be signed in to change notification settings - Fork 3
/
executor.rb
324 lines (287 loc) · 10.8 KB
/
executor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
require './generator'
class ExecutorGenerator < Generator
def self.filter_key
"executor"
end
def initialize
super
@need_guest = false
@noguest_types = Set.new(["void"])
@expand_common = false
end
def need_guest
if @need_guest then
return yield
else
@need_guest = true
result = yield
@need_guest = false
return result
end
end
def type_needs_guest?(type)
size_of_type(type) != 1 && ! @noguest_types.include?(type)
end
def guestify_type(type, guest)
type.strip!
return type, "", "" if not type_needs_guest?(type)
if type =~ /^(.*)(\[[^\[\]]*\])$/ then
post = $2
type1, _, _ = guestify_type($1, true)
#if guest then
# return "GUEST<#{type1}#{post}>", "", ""
#else
return type1, "", post
#end
elsif type =~ /^(.*)\*$/ then
type1, _, _ = guestify_type($1, true)
if guest then
return "GUEST<#{type1}*>", "", ""
else
return type1, "*", ""
end
elsif guest then
if type =~ /^const[ \t]+(.*)$/ then
if type_needs_guest?($1) then
return "const GUEST<#{$1}>"
else
return type
end
else
return "GUEST<#{type}>"
end
else
return type, "", ""
end
end
def decl(type, thing=nil)
t1, pre, post = guestify_type(type, @need_guest)
return "#{t1} #{pre}#{thing}#{post}"
end
def convert_expression(expr)
return expr.gsub(/\'([^\']+)\'/) {|x| "\"#{$1}\"_4"}
end
def declare_struct_union(what, value)
@noguest_types << value["name"]
@out << "#{what} #{value["name"]}"
if value["members"] then
@out << "{"
@out << "GUEST_STRUCT;"
need_guest { declare_members(value["members"]) }
@out << "}"
end
@out << ";"
if value["size"] then
@out << "static_assert(sizeof(#{value["name"]}) == #{value["size"]});"
end
end
def declare_dispatcher(value, extern:false)
@available_dispatchers << value["name"]
@out << "EXTERN_" if extern
@out << "DISPATCHER_TRAP(#{value["name"]}, "
@out << "#{hexlit(value["trap"])}, #{value["selector-location"]});\n"
end
def declare_lowmem(value)
@out << "const LowMemGlobal<#{decl(value["type"])}> #{value["name"]}"
@out << "{ #{hexlit(value["address"],12)} };\n"
# @out << "LOWMEM_ACCESSOR(#{value["name"]});\n"
if value["type"] =~ /^(.*)\[[^\[\]]*\]$/ then
# @out << "inline GUEST<#{$1}>* LMGet#{value["name"]}() { return LM(#{value["name"]}); }\n"
# @out << "NOTRAP_FUNCTION2(LMGet#{value["name"]});\n"
else
sz = size_of_type(value["type"])
if !sz || sz > 4 then
@out << "inline void LMGet#{value["name"]}(#{decl(value["type"]+"*", "val")}) { *val = LM(#{value["name"]}); }\n"
@out << "inline void LMSet#{value["name"]}(#{decl("const " + value["type"]+"*", "val")}) { LM(#{value["name"]}) = *val; }\n"
else
@out << "inline #{decl(value["type"])} LMGet#{value["name"]}() { return LM(#{value["name"]}); }\n"
@out << "inline void LMSet#{value["name"]}(#{decl(value["type"],"val")}) { LM(#{value["name"]}) = val; }\n"
end
@out << "NOTRAP_FUNCTION2(LMGet#{value["name"]});\n"
@out << "NOTRAP_FUNCTION2(LMSet#{value["name"]});\n"
end
end
def handle_regcall_conv(fun)
args = (fun["args"] or [])
@out << (fun["returnreg"] or "void")
argregs = args.map do |arg|
basetype = $1 if arg["type"] =~ /^(.*)\* *$/
if arg["register"] =~ /^Out<(.*)>$/ then
"Out<#{basetype}, #{$1}>"
elsif arg["register"] =~ /^InOut<(.*)>$/ then
"InOut<#{basetype}, #{$1}>"
else
arg["register"]
end
end
@out << "(" << argregs.join(", ") << ")"
@out << ", " << fun["executor_extras"] if fun["executor_extras"]
end
def declare_function(fun)
if fun["dispatcher"] && ! @available_dispatchers.include?(fun["dispatcher"]) then
disp = $global_name_map[fun["dispatcher"]]
if disp and disp["dispatcher"] then
declare_dispatcher(disp["dispatcher"], extern:true)
end
end
name = fun["name"]
dispatcher = (fun["dispatcher"] && $global_name_map[fun["dispatcher"]]["dispatcher"])
trap = (fun["trap"] or (dispatcher and dispatcher["trap"]))
cname = name
if fun["executor"] then
if fun["executor"].is_a?(String) then
if fun["executor"] =~ /_$/ then
cname = fun["executor"] + name
else
cname = fun["executor"]
end
end
end
two = name == cname ? "2" : ""
@out << (fun["return"] or "void") << " " << cname
args = (fun["args"] or [])
@out << "(" << (args.map {|arg| decl(arg["type"], arg["name"])}).join(", ") << ");"
if fun["file_trap"] == "hfs" then
trap_sel_disp = hexlit(Integer(trap) & 0xA0FF)
else
trap_sel_disp = hexlit(trap)
end
if fun["selector"] then
sub = "SUB"
trap_sel_disp += ", #{hexlit(fun["selector"])}, #{hexlit(fun["dispatcher"])}"
else
sub = ""
end
if not fun["executor"] then
elsif fun["file_trap"] == "mfs" then
elsif fun["file_trap"] == "hfs" then
@out << "HFS_#{sub}TRAP(#{name.gsub(/^PBH/,"PB")}, #{name}, "
@out << "#{fun["args"][0]["type"]}, #{trap_sel_disp});"
elsif fun["file_trap"] then
@out << "FILE_#{sub}TRAP(#{name}, #{fun["args"][0]["type"]}, #{trap_sel_disp});"
elsif trap && (fun["executor_extras"] || fun["returnreg"] || args.any? {|arg| arg["register"]}) then
if fun["variants"] then
variants = fun["variants"]
nflagstr = variants.size >= 3 ? "2" : ""
@out << "REGISTER_#{nflagstr}FLAG_TRAP(#{cname}, #{variants.join(", ")}, "
@out << "#{hexlit(trap)}, "
@out << (fun["return"] or "void")
args1 = variants.size >= 3 ? fun["args"][0..-3] : fun["args"][0..-2]
@out << "(" << (args1.map {|arg| decl(arg["type"])}).join(", ") << ")"
@out << ", "
else
@out << "REGISTER_#{sub}TRAP#{two}(#{name}, #{trap_sel_disp}, "
end
handle_regcall_conv(fun)
@out << ");\n"
elsif fun["selector"] then
@out << "PASCAL_SUBTRAP(#{name}, #{hexlit(trap)}, "
@out << "#{hexlit(fun["selector"])}, #{hexlit(fun["dispatcher"])});\n"
elsif trap then
if name == cname then
if args.size == 0 && !fun["return"] then
@out << "REGISTER_TRAP2(#{name}, #{hexlit(trap)}, void());\n"
else
end
else
@out << "PASCAL_TRAP(#{name}, #{hexlit(trap)});\n"
end
else
@out << "NOTRAP_FUNCTION#{two}(#{name});\n"
end
end
def declare_funptr(value)
name = value["name"]
args = (value["args"] or [])
@out << "using #{name} = UPP<"
@out << (value["return"] or "void") << "("
args = (value["args"] or [])
@out << args.map {|arg|decl(arg["type"], arg["name"])}.join(", ")
@out << ")"
if value["returnreg"] || value["executor_extras"] || args.any? {|arg| arg["register"]} then
@out << ", Register<"
handle_regcall_conv(value)
@out << ">"
elsif value["callconv"] == "C" then
@out << ", callconv::CCall"
end
@out << ">;\n"
end
def declare_verbatim(value)
@out << "BEGIN_EXECUTOR_ONLY\n"
@out << value.strip << "\n"
@out << "END_EXECUTOR_ONLY\n"
end
def remap_name(name)
name == "MacTypes" ? "ExMacTypes" : name
end
def generate_preamble(header)
super
@out << "#pragma once\n"
#if header.name == "MacTypes" then
@out << "#include \"base/mactype.h\"\n"
@out << "#include <cassert>\n"
@out << "#include <base/lowglobals.h>\n"
#end
header.included.each do |file|
@out << "#include \"#{remap_name(file)}.h\"\n"
end
@out << "\n"
@out << "#define MODULE_NAME #{header.name}\n"
@out << "#include <base/api-module.h>\n"
@out << "\n\n"
@out << "namespace Executor {\n\n"
end
def generate_postamble(header)
@out << "} /* namespace Executor */"
end
def generate_header(header)
@current_header = header
@available_dispatchers = Set.new
super
end
def make_api_ifdef(api)
if api == "carbon" then
else
yield
end
end
def generate(defs)
print "Writing Headers...\n"
FileUtils.mkdir_p "#{$options.output_dir}/api"
FileUtils.mkdir_p "#{$options.output_dir}/trap_instances"
moduleList = []
defs.topsort.each do |name|
name2 = remap_name(name)
moduleList << name2
formatted_file "#{$options.output_dir}/api/#{name2}.h" do |f|
f << generate_header(defs.headers[name])
end
formatted_file "#{$options.output_dir}/trap_instances/#{name2}.cpp" do |f|
f << <<END
#define INSTANTIATE_TRAPS_#{name2}
#include <#{name2}.h>
// Function for preventing the linker from considering the static constructors in this module unused
namespace Executor::ReferenceTraps {
void #{name2}() {}
}
END
end
end
formatted_file "#{$options.output_dir}/trap_instances/ReferenceAllTraps.cpp" do |f|
f << "namespace Executor {\n"
f << "namespace ReferenceTraps {\n"
moduleList.each { |m| f << "void #{m}();\n" }
f << "}\nvoid ReferenceAllTraps() {\n"
moduleList.each { |m| f << "ReferenceTraps::#{m}();\n" }
f << "}\n}\n"
end
File.open "#{$options.output_dir}/trap_instances/trap_instances.cmake", "w" do |f|
f << "set(trap_instance_sources\n"
f << " \"#{$options.output_dir}/trap_instances/ReferenceAllTraps.cpp\"\n"
moduleList.each { |m| f << " \"#{$options.output_dir}/trap_instances/#{m}.cpp\"\n" }
f << ")\n"
end
print "Done.\n"
end
end