1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 # This script generates jit/CacheIROpsGenerated.h from CacheIROps.yaml
7 from collections
import OrderedDict
12 from mozbuild
.preprocessor
import Preprocessor
14 HEADER_TEMPLATE
= """\
15 /* This Source Code Form is subject to the terms of the Mozilla Public
16 * License, v. 2.0. If a copy of the MPL was not distributed with this
17 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
19 #ifndef %(includeguard)s
20 #define %(includeguard)s
22 /* This file is generated by jit/GenerateCacheIRFiles.py. Do not edit! */
26 #endif // %(includeguard)s
30 def generate_header(c_out
, includeguard
, contents
):
34 "includeguard": includeguard
,
40 def load_yaml(yaml_path
):
41 # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in
44 pp
.context
.update(buildconfig
.defines
["ALLDEFINES"])
45 pp
.out
= six
.StringIO()
46 pp
.do_filter("substitution")
47 pp
.do_include(yaml_path
)
48 contents
= pp
.out
.getvalue()
50 # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7+
51 # also preserves ordering for normal dictionaries.
52 # Code based on https://stackoverflow.com/a/21912744.
53 class OrderedLoader(yaml
.Loader
):
56 def construct_mapping(loader
, node
):
57 loader
.flatten_mapping(node
)
58 return OrderedDict(loader
.construct_pairs(node
))
60 tag
= yaml
.resolver
.BaseResolver
.DEFAULT_MAPPING_TAG
61 OrderedLoader
.add_constructor(tag
, construct_mapping
)
62 return yaml
.load(contents
, OrderedLoader
)
65 # Information for generating CacheIRWriter code for a single argument. Tuple
66 # stores the C++ argument type and the CacheIRWriter method to call.
68 "ValId": ("ValOperandId", "writeOperandId"),
69 "ObjId": ("ObjOperandId", "writeOperandId"),
70 "StringId": ("StringOperandId", "writeOperandId"),
71 "SymbolId": ("SymbolOperandId", "writeOperandId"),
72 "BooleanId": ("BooleanOperandId", "writeOperandId"),
73 "Int32Id": ("Int32OperandId", "writeOperandId"),
74 "NumberId": ("NumberOperandId", "writeOperandId"),
75 "BigIntId": ("BigIntOperandId", "writeOperandId"),
76 "ValueTagId": ("ValueTagOperandId", "writeOperandId"),
77 "IntPtrId": ("IntPtrOperandId", "writeOperandId"),
78 "RawId": ("OperandId", "writeOperandId"),
79 "ShapeField": ("Shape*", "writeShapeField"),
80 "WeakShapeField": ("Shape*", "writeWeakShapeField"),
81 "GetterSetterField": ("GetterSetter*", "writeGetterSetterField"),
82 "ObjectField": ("JSObject*", "writeObjectField"),
83 "StringField": ("JSString*", "writeStringField"),
84 "AtomField": ("JSAtom*", "writeStringField"),
85 "SymbolField": ("JS::Symbol*", "writeSymbolField"),
86 "BaseScriptField": ("BaseScript*", "writeBaseScriptField"),
87 "JitCodeField": ("JitCode*", "writeJitCodeField"),
88 "RawInt32Field": ("uint32_t", "writeRawInt32Field"),
89 "RawPointerField": ("const void*", "writeRawPointerField"),
90 "IdField": ("jsid", "writeIdField"),
91 "ValueField": ("const Value&", "writeValueField"),
92 "RawInt64Field": ("uint64_t", "writeRawInt64Field"),
93 "DoubleField": ("double", "writeDoubleField"),
94 "AllocSiteField": ("gc::AllocSite*", "writeAllocSiteField"),
95 "JSOpImm": ("JSOp", "writeJSOpImm"),
96 "BoolImm": ("bool", "writeBoolImm"),
97 "ByteImm": ("uint32_t", "writeByteImm"), # uint32_t to enable fits-in-byte asserts.
98 "GuardClassKindImm": ("GuardClassKind", "writeGuardClassKindImm"),
99 "ValueTypeImm": ("ValueType", "writeValueTypeImm"),
100 "JSWhyMagicImm": ("JSWhyMagic", "writeJSWhyMagicImm"),
101 "CallFlagsImm": ("CallFlags", "writeCallFlagsImm"),
102 "ScalarTypeImm": ("Scalar::Type", "writeScalarTypeImm"),
103 "UnaryMathFunctionImm": ("UnaryMathFunction", "writeUnaryMathFunctionImm"),
104 "WasmValTypeImm": ("wasm::ValType::Kind", "writeWasmValTypeImm"),
105 "Int32Imm": ("int32_t", "writeInt32Imm"),
106 "UInt32Imm": ("uint32_t", "writeUInt32Imm"),
107 "JSNativeImm": ("JSNative", "writeJSNativeImm"),
108 "StaticStringImm": ("const char*", "writeStaticStringImm"),
109 "AllocKindImm": ("gc::AllocKind", "writeAllocKindImm"),
110 "CompletionKindImm": ("CompletionKind", "writeCompletionKindImm"),
114 def gen_writer_method(name
, args
, custom_writer
):
115 """Generates a CacheIRWRiter method for a single opcode."""
117 # Generate a single method that writes the opcode and each argument.
120 # void guardShape(ObjOperandId obj, Shape* shape) {
121 # writeOp(CacheOp::GuardShape);
122 # writeOperandId(obj);
123 # writeShapeField(shape);
124 # assertLengthMatches();
127 # The assertLengthMatches() call is to assert the information in the
128 # arg_length dictionary below matches what's written.
130 # Method names start with a lowercase letter.
131 method_name
= name
[0].lower() + name
[1:]
139 for arg_name
, arg_type
in six
.iteritems(args
):
140 cpp_type
, write_method
= arg_writer_info
[arg_type
]
141 if arg_name
== "result":
143 args_code
+= " {} result(newOperandId());\\\n".format(cpp_type
)
144 args_code
+= " writeOperandId(result);\\\n"
146 method_args
.append("{} {}".format(cpp_type
, arg_name
))
147 args_code
+= " {}({});\\\n".format(write_method
, arg_name
)
151 code
+= "private:\\\n"
152 code
+= "{} {}({}) {{\\\n".format(ret_type
, method_name
, ", ".join(method_args
))
153 code
+= " writeOp(CacheOp::{});\\\n".format(name
)
155 code
+= " assertLengthMatches();\\\n"
156 if ret_type
!= "void":
157 code
+= " return result;\\\n"
160 code
+= "\\\npublic:"
164 # Information for generating code using CacheIRReader for a single argument.
165 # Tuple stores the C++ type, the suffix used for arguments/variables of this
166 # type, and the expression to read this type from CacheIRReader.
168 "ValId": ("ValOperandId", "Id", "reader.valOperandId()"),
169 "ObjId": ("ObjOperandId", "Id", "reader.objOperandId()"),
170 "StringId": ("StringOperandId", "Id", "reader.stringOperandId()"),
171 "SymbolId": ("SymbolOperandId", "Id", "reader.symbolOperandId()"),
172 "BooleanId": ("BooleanOperandId", "Id", "reader.booleanOperandId()"),
173 "Int32Id": ("Int32OperandId", "Id", "reader.int32OperandId()"),
174 "NumberId": ("NumberOperandId", "Id", "reader.numberOperandId()"),
175 "BigIntId": ("BigIntOperandId", "Id", "reader.bigIntOperandId()"),
176 "ValueTagId": ("ValueTagOperandId", "Id", "reader.valueTagOperandId()"),
177 "IntPtrId": ("IntPtrOperandId", "Id", "reader.intPtrOperandId()"),
178 "RawId": ("uint32_t", "Id", "reader.rawOperandId()"),
179 "ShapeField": ("uint32_t", "Offset", "reader.stubOffset()"),
180 "WeakShapeField": ("uint32_t", "Offset", "reader.stubOffset()"),
181 "GetterSetterField": ("uint32_t", "Offset", "reader.stubOffset()"),
182 "ObjectField": ("uint32_t", "Offset", "reader.stubOffset()"),
183 "StringField": ("uint32_t", "Offset", "reader.stubOffset()"),
184 "AtomField": ("uint32_t", "Offset", "reader.stubOffset()"),
185 "SymbolField": ("uint32_t", "Offset", "reader.stubOffset()"),
186 "BaseScriptField": ("uint32_t", "Offset", "reader.stubOffset()"),
187 "JitCodeField": ("uint32_t", "Offset", "reader.stubOffset()"),
188 "RawInt32Field": ("uint32_t", "Offset", "reader.stubOffset()"),
189 "RawPointerField": ("uint32_t", "Offset", "reader.stubOffset()"),
190 "IdField": ("uint32_t", "Offset", "reader.stubOffset()"),
191 "ValueField": ("uint32_t", "Offset", "reader.stubOffset()"),
192 "RawInt64Field": ("uint32_t", "Offset", "reader.stubOffset()"),
193 "DoubleField": ("uint32_t", "Offset", "reader.stubOffset()"),
194 "AllocSiteField": ("uint32_t", "Offset", "reader.stubOffset()"),
195 "JSOpImm": ("JSOp", "", "reader.jsop()"),
196 "BoolImm": ("bool", "", "reader.readBool()"),
197 "ByteImm": ("uint8_t", "", "reader.readByte()"),
198 "GuardClassKindImm": ("GuardClassKind", "", "reader.guardClassKind()"),
199 "ValueTypeImm": ("ValueType", "", "reader.valueType()"),
200 "JSWhyMagicImm": ("JSWhyMagic", "", "reader.whyMagic()"),
201 "CallFlagsImm": ("CallFlags", "", "reader.callFlags()"),
202 "ScalarTypeImm": ("Scalar::Type", "", "reader.scalarType()"),
203 "UnaryMathFunctionImm": ("UnaryMathFunction", "", "reader.unaryMathFunction()"),
204 "WasmValTypeImm": ("wasm::ValType::Kind", "", "reader.wasmValType()"),
205 "Int32Imm": ("int32_t", "", "reader.int32Immediate()"),
206 "UInt32Imm": ("uint32_t", "", "reader.uint32Immediate()"),
207 "JSNativeImm": ("JSNative", "", "reinterpret_cast<JSNative>(reader.pointer())"),
208 "StaticStringImm": ("const char*", "", "reinterpret_cast<char*>(reader.pointer())"),
209 "AllocKindImm": ("gc::AllocKind", "", "reader.allocKind()"),
210 "CompletionKindImm": ("CompletionKind", "", "reader.completionKind()"),
214 def gen_compiler_method(name
, args
):
215 """Generates CacheIRCompiler or WarpCacheIRTranspiler header code for a
218 method_name
= "emit" + name
220 # We generate the signature of the method that needs to be implemented and a
221 # separate function forwarding to it. For example:
223 # [[nodiscard]] bool emitGuardShape(ObjOperandId objId, uint32_t shapeOffset);
224 # [[nodiscard]] bool emitGuardShape(CacheIRReader& reader) {
225 # ObjOperandId objId = reader.objOperandId();
226 # uint32_t shapeOffset = reader.stubOffset();
227 # return emitGuardShape(objId, shapeOffset);
233 for arg_name
, arg_type
in six
.iteritems(args
):
234 cpp_type
, suffix
, readexpr
= arg_reader_info
[arg_type
]
235 cpp_name
= arg_name
+ suffix
236 cpp_args
.append(cpp_name
)
237 method_args
.append("{} {}".format(cpp_type
, cpp_name
))
238 args_code
+= " {} {} = {};\\\n".format(cpp_type
, cpp_name
, readexpr
)
240 # Generate signature.
241 code
= "[[nodiscard]] bool {}({});\\\n".format(method_name
, ", ".join(method_args
))
243 # Generate the method forwarding to it.
244 code
+= "[[nodiscard]] bool {}(CacheIRReader& reader) {{\\\n".format(method_name
)
246 code
+= " return {}({});\\\n".format(method_name
, ", ".join(cpp_args
))
252 # For each argument type, the method name for printing it.
253 arg_spewer_method
= {
254 "ValId": "spewOperandId",
255 "ObjId": "spewOperandId",
256 "StringId": "spewOperandId",
257 "SymbolId": "spewOperandId",
258 "BooleanId": "spewOperandId",
259 "Int32Id": "spewOperandId",
260 "NumberId": "spewOperandId",
261 "BigIntId": "spewOperandId",
262 "ValueTagId": "spewOperandId",
263 "IntPtrId": "spewOperandId",
264 "RawId": "spewRawOperandId",
265 "ShapeField": "spewField",
266 "WeakShapeField": "spewField",
267 "GetterSetterField": "spewField",
268 "ObjectField": "spewField",
269 "StringField": "spewField",
270 "AtomField": "spewField",
271 "SymbolField": "spewField",
272 "BaseScriptField": "spewField",
273 "JitCodeField": "spewField",
274 "RawInt32Field": "spewField",
275 "RawPointerField": "spewField",
276 "IdField": "spewField",
277 "ValueField": "spewField",
278 "RawInt64Field": "spewField",
279 "DoubleField": "spewField",
280 "AllocSiteField": "spewField",
281 "JSOpImm": "spewJSOpImm",
282 "BoolImm": "spewBoolImm",
283 "ByteImm": "spewByteImm",
284 "GuardClassKindImm": "spewGuardClassKindImm",
285 "ValueTypeImm": "spewValueTypeImm",
286 "JSWhyMagicImm": "spewJSWhyMagicImm",
287 "CallFlagsImm": "spewCallFlagsImm",
288 "ScalarTypeImm": "spewScalarTypeImm",
289 "UnaryMathFunctionImm": "spewUnaryMathFunctionImm",
290 "WasmValTypeImm": "spewWasmValTypeImm",
291 "Int32Imm": "spewInt32Imm",
292 "UInt32Imm": "spewUInt32Imm",
293 "JSNativeImm": "spewJSNativeImm",
294 "StaticStringImm": "spewStaticStringImm",
295 "AllocKindImm": "spewAllocKindImm",
296 "CompletionKindImm": "spewCompletionKindImm",
300 def gen_spewer_method(name
, args
):
301 """Generates spewer code for a single opcode."""
303 method_name
= "spew" + name
305 # Generate code like this:
307 # void spewGuardShape(CacheIRReader& reader) {
308 # spewOp(CacheOp::GuardShape);
309 # spewOperandId("objId", reader.objOperandId());
310 # spewOperandSeparator();
311 # spewField("shapeOffset", reader.stubOffset());
317 for arg_name
, arg_type
in six
.iteritems(args
):
318 _
, suffix
, readexpr
= arg_reader_info
[arg_type
]
320 spew_method
= arg_spewer_method
[arg_type
]
322 args_code
+= " spewArgSeparator();\\\n"
323 args_code
+= ' {}("{}", {});\\\n'.format(spew_method
, arg_name
, readexpr
)
326 code
= "void {}(CacheIRReader& reader) {{\\\n".format(method_name
)
327 code
+= " spewOp(CacheOp::{});\\\n".format(name
)
329 code
+= " spewOpEnd();\\\n"
335 def gen_clone_method(name
, args
):
336 """Generates code for cloning a single opcode."""
338 method_name
= "clone" + name
340 # Generate code like this:
342 # void cloneGuardShape(CacheIRReader& reader, CacheIRWriter& writer) {
343 # writer.writeOp(CacheOp::GuardShape);
344 # ObjOperandId objId = reader.objOperandId();
345 # writer.writeOperandId(objId);
346 # uint32_t shapeOffset = reader.stubOffset();
347 # Shape* shape = getShapeField(shapeOffset);
348 # writer.writeShapeField(shape);
349 # writer.assertLengthMatches();
354 for arg_name
, arg_type
in six
.iteritems(args
):
355 if arg_type
== "RawId":
358 read_type
, suffix
, readexpr
= arg_reader_info
[arg_type
]
359 read_name
= arg_name
+ suffix
360 value_name
= read_name
361 args_code
+= " {} {} = {};\\\n".format(read_type
, read_name
, readexpr
)
363 write_type
, write_method
= arg_writer_info
[arg_type
]
364 if arg_name
== "result":
365 args_code
+= " writer.newOperandId();\\\n"
366 if suffix
== "Offset":
367 # If the write function takes T&, the intermediate variable
368 # should be of type T.
369 if write_type
.endswith("&"):
370 write_type
= write_type
[:-1]
371 value_name
= arg_name
372 args_code
+= " {} {} = get{}({});\\\n".format(
373 write_type
, value_name
, arg_type
, read_name
375 args_code
+= " writer.{}({});\\\n".format(write_method
, value_name
)
377 code
= "void {}".format(method_name
)
378 code
+= "(CacheIRReader& reader, CacheIRWriter& writer) {{\\\n"
379 code
+= " writer.writeOp(CacheOp::{});\\\n".format(name
)
381 code
+= " writer.assertLengthMatches();\\\n"
387 # Length in bytes for each argument type, either an integer or a C++ expression.
388 # This is used to generate the CacheIROpArgLengths array. CacheIRWriter asserts
389 # the number of bytes written matches the value in that array.
404 "GetterSetterField": 1,
409 "BaseScriptField": 1,
412 "RawPointerField": 1,
422 "UnaryMathFunctionImm": 1,
425 "GuardClassKindImm": 1,
430 "JSNativeImm": "sizeof(uintptr_t)",
431 "StaticStringImm": "sizeof(uintptr_t)",
433 "CompletionKindImm": 1,
437 def generate_cacheirops_header(c_out
, yaml_path
):
438 """Generate CacheIROpsGenerated.h from CacheIROps.yaml. The generated file
439 contains a list of all CacheIR ops and generated source code for
440 CacheIRWriter and CacheIRCompiler."""
442 data
= load_yaml(yaml_path
)
444 # CACHE_IR_OPS items. Each item stores an opcode name and arguments length
445 # expression. For example: _(GuardShape, 1 + 1)
448 # Generated CacheIRWriter methods.
451 # Generated CacheIRCompiler methods.
452 compiler_shared_methods
= []
453 compiler_unshared_methods
= []
455 # Generated WarpCacheIRTranspiler methods.
456 transpiler_methods
= []
458 # List of ops supported by WarpCacheIRTranspiler.
461 # Generated methods for spewers.
464 # Generated methods for cloning IC stubs
471 assert args
is None or isinstance(args
, OrderedDict
)
473 shared
= op
["shared"]
474 assert isinstance(shared
, bool)
476 transpile
= op
["transpile"]
477 assert isinstance(transpile
, bool)
479 # Unscored Ops default to UINT32_MAX
480 cost_estimate
= op
.get("cost_estimate", int(0xFFFFFFFF))
481 assert isinstance(cost_estimate
, int)
483 custom_writer
= op
.get("custom_writer", False)
484 assert isinstance(custom_writer
, bool)
487 args_length
= " + ".join([str(arg_length
[v
]) for v
in args
.values()])
491 transpile_str
= "true" if transpile
else "false"
493 "_({}, {}, {}, {})".format(name
, args_length
, transpile_str
, cost_estimate
)
496 writer_methods
.append(gen_writer_method(name
, args
, custom_writer
))
499 compiler_shared_methods
.append(gen_compiler_method(name
, args
))
501 compiler_unshared_methods
.append(gen_compiler_method(name
, args
))
504 transpiler_methods
.append(gen_compiler_method(name
, args
))
505 transpiler_ops
.append("_({})".format(name
))
507 spewer_methods
.append(gen_spewer_method(name
, args
))
509 clone_methods
.append(gen_clone_method(name
, args
))
511 contents
= "#define CACHE_IR_OPS(_)\\\n"
512 contents
+= "\\\n".join(ops_items
)
515 contents
+= "#define CACHE_IR_WRITER_GENERATED \\\n"
516 contents
+= "\\\n".join(writer_methods
)
519 contents
+= "#define CACHE_IR_COMPILER_SHARED_GENERATED \\\n"
520 contents
+= "\\\n".join(compiler_shared_methods
)
523 contents
+= "#define CACHE_IR_COMPILER_UNSHARED_GENERATED \\\n"
524 contents
+= "\\\n".join(compiler_unshared_methods
)
527 contents
+= "#define CACHE_IR_TRANSPILER_GENERATED \\\n"
528 contents
+= "\\\n".join(transpiler_methods
)
531 contents
+= "#define CACHE_IR_TRANSPILER_OPS(_)\\\n"
532 contents
+= "\\\n".join(transpiler_ops
)
535 contents
+= "#define CACHE_IR_SPEWER_GENERATED \\\n"
536 contents
+= "\\\n".join(spewer_methods
)
539 contents
+= "#define CACHE_IR_CLONE_GENERATED \\\n"
540 contents
+= "\\\n".join(clone_methods
)
543 generate_header(c_out
, "jit_CacheIROpsGenerated_h", contents
)