summaryrefslogtreecommitdiffstats
path: root/js/src/jit/GenerateLIRFiles.py
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/GenerateLIRFiles.py')
-rw-r--r--js/src/jit/GenerateLIRFiles.py298
1 files changed, 298 insertions, 0 deletions
diff --git a/js/src/jit/GenerateLIRFiles.py b/js/src/jit/GenerateLIRFiles.py
new file mode 100644
index 0000000000..86882966fd
--- /dev/null
+++ b/js/src/jit/GenerateLIRFiles.py
@@ -0,0 +1,298 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This script generates jit/LIROpsGenerated.h (list of LIR instructions)
+# from LIROps.yaml.
+
+from collections import OrderedDict
+
+import buildconfig
+import six
+import yaml
+from mozbuild.preprocessor import Preprocessor
+
+HEADER_TEMPLATE = """\
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef %(includeguard)s
+#define %(includeguard)s
+
+/* This file is generated by jit/GenerateLIRFiles.py. Do not edit! */
+
+%(contents)s
+
+#endif // %(includeguard)s
+"""
+
+
+def load_yaml(yaml_path):
+ # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in
+ # the YAML file.
+ pp = Preprocessor()
+ pp.context.update(buildconfig.defines["ALLDEFINES"])
+ pp.out = six.StringIO()
+ pp.do_filter("substitution")
+ pp.do_include(yaml_path)
+ contents = pp.out.getvalue()
+
+ # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7
+ # also preserves ordering for normal dictionaries.
+ # Code based on https://stackoverflow.com/a/21912744.
+ class OrderedLoader(yaml.Loader):
+ pass
+
+ def construct_mapping(loader, node):
+ loader.flatten_mapping(node)
+ return OrderedDict(loader.construct_pairs(node))
+
+ tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
+ OrderedLoader.add_constructor(tag, construct_mapping)
+ return yaml.load(contents, OrderedLoader)
+
+
+def generate_header(c_out, includeguard, contents):
+ c_out.write(
+ HEADER_TEMPLATE
+ % {
+ "includeguard": includeguard,
+ "contents": contents,
+ }
+ )
+
+
+operand_types = {
+ "WordSized": "LAllocation",
+ "BoxedValue": "LBoxAllocation",
+ "Int64": "LInt64Allocation",
+}
+
+
+result_types = {
+ "WordSized": "1",
+ "BoxedValue": "BOX_PIECES",
+ "Int64": "INT64_PIECES",
+}
+
+
+def gen_helper_template_value(num_regular_allocs, num_value_allocs, num_int64_allocs):
+ template_str = ""
+ if num_value_allocs:
+ template_str += str(num_value_allocs) + " * BOX_PIECES + "
+ if num_int64_allocs:
+ template_str += str(num_int64_allocs) + " * INT64_PIECES + "
+ template_str += str(num_regular_allocs)
+ return template_str
+
+
+def build_index_def(num_specials_operands, index_value, num_reg_operands, piece):
+ if num_specials_operands:
+ return " static const size_t {} = {} + {} * {};\\\n".format(
+ index_value, num_reg_operands, piece, num_specials_operands
+ )
+ else:
+ return " static const size_t {} = {};\\\n".format(
+ index_value, num_reg_operands
+ )
+
+
+def gen_lir_class(
+ name, result_type, operands, arguments, num_temps, call_instruction, mir_op
+):
+ """Generates class definition for a single LIR opcode."""
+ class_name = "L" + name
+
+ getters = []
+ setters = []
+ # Operand index definitions.
+ oper_indices = []
+ # Parameters for the class constructor.
+ constructor_params = []
+
+ num_reg_operands = 0
+ num_value_operands = 0
+ num_int64_operands = 0
+ if operands:
+ # Get number of LAllocations to use for defining indices.
+ for operand in operands:
+ if operands[operand] == "WordSized":
+ num_reg_operands += 1
+
+ current_reg_oper = 0
+ for operand in operands:
+ op_type = operands[operand]
+ op_alloc_type = operand_types[op_type]
+ constructor_params.append("const " + op_alloc_type + "& " + operand)
+ if op_type == "WordSized":
+ index_value = str(current_reg_oper)
+ current_reg_oper += 1
+ getters.append(
+ " const "
+ + op_alloc_type
+ + "* "
+ + operand
+ + "() { return getOperand("
+ + index_value
+ + "); }"
+ )
+ setters.append(" setOperand(" + index_value + ", " + operand + ");")
+ elif op_type == "BoxedValue":
+ index_value = operand[0].upper() + operand[1:] + "Index"
+ oper_indices.append(
+ build_index_def(
+ num_value_operands, index_value, num_reg_operands, "BOX_PIECES"
+ )
+ )
+ num_value_operands += 1
+ # No getters generated for BoxedValue operands.
+ setters.append(
+ " setBoxOperand(" + index_value + ", " + operand + ");"
+ )
+ elif op_type == "Int64":
+ index_value = operand[0].upper() + operand[1:] + "Index"
+ oper_indices.append(
+ build_index_def(
+ num_int64_operands,
+ index_value,
+ num_reg_operands,
+ "INT64_PIECES",
+ )
+ )
+ num_int64_operands += 1
+ getters.append(
+ " const "
+ + op_alloc_type
+ + " "
+ + operand
+ + "() { return getInt64Operand("
+ + index_value
+ + "); }"
+ )
+ setters.append(
+ " setInt64Operand(" + index_value + ", " + operand + ");"
+ )
+ else:
+ raise Exception("Invalid operand type: " + op_type)
+ if num_temps:
+ for temp in range(num_temps):
+ constructor_params.append("const LDefinition& temp" + str(temp))
+ setters.append(" setTemp(" + str(temp) + ", temp" + str(temp) + ");")
+ getters.append(
+ " const LDefinition* temp"
+ + str(temp)
+ + "() { return getTemp("
+ + str(temp)
+ + "); }"
+ )
+ code = "class {} : public LInstructionHelper<".format(class_name)
+ if result_type:
+ code += result_types[result_type] + ", "
+ else:
+ code += "0, "
+ code += gen_helper_template_value(
+ num_reg_operands, num_value_operands, num_int64_operands
+ )
+ code += ", {}> {{\\\n".format(num_temps)
+ if arguments:
+ for arg_name in arguments:
+ arg_type_sig = arguments[arg_name]
+ constructor_params.append(arg_type_sig + " " + arg_name)
+ code += " " + arg_type_sig + " " + arg_name + "_;\\\n"
+ code += " public:\\\n LIR_HEADER({})\\\n".format(name)
+ code += " explicit {}(".format(class_name)
+ code += ", ".join(constructor_params)
+ code += ") : LInstructionHelper(classOpcode)"
+ if arguments:
+ for arg_name in arguments:
+ code += ", " + arg_name + "_(" + arg_name + ")"
+ code += " {"
+ if call_instruction:
+ code += "\\\n this->setIsCall();"
+ code += "\\\n"
+ code += "\\\n".join(setters)
+ code += "\\\n }\\\n"
+ code += "\\\n".join(getters)
+ if arguments:
+ for arg_name in arguments:
+ code += " " + arguments[arg_name] + " " + arg_name + "() const { "
+ code += "return " + arg_name + "_; }\\\n"
+ code += "\\\n"
+ if operands:
+ code += "\\\n".join(oper_indices)
+ if mir_op:
+ if mir_op is True:
+ code += " M{}* mir() const {{ return mir_->to{}(); }};\\\n".format(
+ name, name
+ )
+ else:
+ code += " M{}* mir() const {{ return mir_->to{}(); }};\\\n".format(
+ mir_op, mir_op
+ )
+ code += "};\\\n"
+ return code
+
+
+def generate_lir_header(c_out, yaml_path):
+ data = load_yaml(yaml_path)
+
+ # LIR_OPCODE_LIST opcode.
+ ops = []
+
+ # Generated LIR op class definitions.
+ lir_op_classes = []
+
+ for op in data:
+ name = op["name"]
+
+ gen_boilerplate = op.get("gen_boilerplate", True)
+ assert isinstance(gen_boilerplate, bool)
+
+ if gen_boilerplate:
+ result_type = op.get("result_type", None)
+ assert result_type is None or str
+ if result_type:
+ assert result_types[result_type]
+
+ operands = op.get("operands", None)
+ assert operands is None or OrderedDict
+
+ arguments = op.get("arguments", None)
+ assert arguments is None or isinstance(arguments, OrderedDict)
+
+ num_temps = op.get("num_temps", 0)
+ assert num_temps is None or int
+
+ gen_boilerplate = op.get("gen_boilerplate", True)
+ assert isinstance(gen_boilerplate, bool)
+
+ call_instruction = op.get("call_instruction", None)
+ assert call_instruction is None or True
+
+ mir_op = op.get("mir_op", None)
+ assert mir_op is None or True or str
+
+ lir_op_classes.append(
+ gen_lir_class(
+ name,
+ result_type,
+ operands,
+ arguments,
+ num_temps,
+ call_instruction,
+ mir_op,
+ )
+ )
+
+ ops.append("_({})".format(name))
+
+ contents = "#define LIR_OPCODE_LIST(_)\\\n"
+ contents += "\\\n".join(ops)
+ contents += "\n\n"
+
+ contents += "#define LIR_OPCODE_CLASS_GENERATED \\\n"
+ contents += "\\\n".join(lir_op_classes)
+ contents += "\n\n"
+
+ generate_header(c_out, "jit_LIROpsGenerated_h", contents)