Source code

Revision control

Copy as Markdown

Other Tools

# 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.
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()
return yaml.safe_load(contents)
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 isinstance(operands, dict)
arguments = op.get("arguments", None)
assert arguments is None or isinstance(arguments, dict)
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)