diff options
Diffstat (limited to 'js/src/jit/GenerateABIFunctionType.py')
-rw-r--r-- | js/src/jit/GenerateABIFunctionType.py | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/js/src/jit/GenerateABIFunctionType.py b/js/src/jit/GenerateABIFunctionType.py new file mode 100644 index 0000000000..58478bf0bc --- /dev/null +++ b/js/src/jit/GenerateABIFunctionType.py @@ -0,0 +1,483 @@ +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/GenerateABIFunctionType.py. Do not edit! */ + +%(contents)s + +#endif // %(includeguard)s +""" + + +def generate_header(c_out, includeguard, contents): + c_out.write( + HEADER_TEMPLATE + % { + "includeguard": includeguard, + "contents": contents, + } + ) + + +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 cpp_arg_type(arg_type): + if arg_type == "General": + return "intptr_t" + elif arg_type == "Int32": + return "int32_t" + elif arg_type == "Int64": + return "int64_t" + elif arg_type == "Float32": + return "float" + elif arg_type == "Float64": + return "double" + else: + raise ValueError(arg_type) + + +def func_type_name(func_type): + if "name" in func_type: + return func_type["name"] + + # Autogenerate a name like `General_GeneralGeneral` if none is specified + return f"{func_type['ret']}_{''.join(func_type['args'])}" + + +def func_type_has_floats(func_type): + for arg in func_type["args"]: + if arg == "Float32" or arg == "Float64": + return True + return False + + +# Generate the ARM32 argument loading for a func type for when soft-FP is enabled +def arm32_soft_fp_args(func_type): + # This must match ABIArgGenerator::softNext() in Assembler-arm.cpp + contents = "" + numIntArgRegs = 4 + intRegIndex = 0 + stackOffset = 0 + for i, arg in enumerate(func_type["args"]): + if i != 0: + contents += ", " + + if arg == "General": + if intRegIndex == numIntArgRegs: + contents += f"stack_pointer[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}" + intRegIndex += 1 + elif arg == "Int32": + if intRegIndex == numIntArgRegs: + contents += f"stack_pointer[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}" + intRegIndex += 1 + elif arg == "Int64": + intRegIndex += intRegIndex % 2 + if intRegIndex == numIntArgRegs: + stackOffset += stackOffset % 2 + contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])" + stackOffset += 2 + else: + contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex+1})" + intRegIndex += 2 + elif arg == "Float32": + if intRegIndex == numIntArgRegs: + contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])" + stackOffset += 1 + else: + contents += f"mozilla::BitwiseCast<float>(a{intRegIndex})" + intRegIndex += 1 + elif arg == "Float64": + intRegIndex += intRegIndex % 2 + if intRegIndex == numIntArgRegs: + stackOffset += stackOffset % 2 + contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))" + stackOffset += 2 + else: + contents += f"mozilla::BitwiseCast<double>(MakeInt64(a{intRegIndex}, a{intRegIndex + 1}))" + intRegIndex += 2 + assert intRegIndex <= numIntArgRegs + return contents + + +# Generate the ARM32 argument loading for a func type for when hard-FP is enabled +def arm32_hard_fp_args(func_type): + # This must match ABIArgGenerator::hardNext() in Assembler-arm.cpp + contents = "" + numIntArgRegs = 4 + numFloatArgRegs = 16 + intRegIndex = 0 + floatRegIndex = 0 + stackOffset = 0 + for i, arg in enumerate(func_type["args"]): + if i != 0: + contents += ", " + + if arg == "General": + if intRegIndex == numIntArgRegs: + contents += f"stack_pointer[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}" + intRegIndex += 1 + elif arg == "Int32": + if intRegIndex == numIntArgRegs: + contents += f"stack_pointer[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}" + intRegIndex += 1 + elif arg == "Int64": + intRegIndex += intRegIndex % 2 + if intRegIndex == numIntArgRegs: + stackOffset += stackOffset % 2 + contents += f"MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}])" + stackOffset += 2 + else: + contents += f"MakeInt64(a{intRegIndex}, a{intRegIndex+1})" + intRegIndex += 2 + elif arg == "Float32": + if floatRegIndex == numFloatArgRegs: + contents += f"mozilla::BitwiseCast<float>(stack_pointer[{stackOffset}])" + stackOffset += 1 + else: + contents += f"s{floatRegIndex}" + floatRegIndex += 1 + elif arg == "Float64": + floatRegIndex += floatRegIndex % 2 + if floatRegIndex == numFloatArgRegs: + stackOffset += stackOffset % 2 + contents += f"mozilla::BitwiseCast<double>(MakeInt64(stack_pointer[{stackOffset}], stack_pointer[{stackOffset + 1}]))" + stackOffset += 2 + else: + contents += f"d{round(floatRegIndex / 2)}" + floatRegIndex += 2 + assert intRegIndex <= numIntArgRegs + assert floatRegIndex <= numFloatArgRegs + return contents + + +def arm32_simulator_dispatch(func_types): + contents = "" + for func_type in func_types: + hard_fp_args = arm32_hard_fp_args(func_type) + soft_fp_args = arm32_soft_fp_args(func_type) + ret = func_type["ret"] + + contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n" + contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(external);\\\n" + contents += f" {cpp_arg_type(ret)} ret;\\\n" + if func_type_has_floats(func_type): + contents += " if (UseHardFpABI()) {\\\n" + contents += f" ret = target({hard_fp_args});\\\n" + contents += " } else {\\\n" + contents += f" ret = target({soft_fp_args});\\\n" + contents += " }\\\n" + else: + # No float args means we don't need to check the float ABI and + # either generated args will do. + contents += f" ret = target({soft_fp_args});\\\n" + contents += " scratchVolatileRegisters((void*)target);\\\n" + if ret == "General" or ret == "Int32" or ret == "Int64": + contents += " setCallResult(ret);\\\n" + elif ret == "Float32": + contents += " setCallResultFloat(ret);\\\n" + elif ret == "Float64": + contents += " setCallResultDouble(ret);\\\n" + contents += " break;\\\n" + contents += "}\\\n" + return contents + + +# Generate the ARM64 argument loading for a func type +def arm64_args(func_type): + # This must match ABIArgGenerator::next() in Assembler-arm64.cpp + contents = "" + numIntArgRegs = 8 + numFloatArgRegs = 8 + intRegIndex = 0 + floatRegIndex = 0 + stackOffset = 0 + for i, arg in enumerate(func_type["args"]): + if i != 0: + contents += ", " + + if arg == "General": + if intRegIndex == numIntArgRegs: + contents += f"sp[{stackOffset}]" + stackOffset += 1 + else: + contents += f"x{intRegIndex}" + intRegIndex += 1 + elif arg == "Int32": + if intRegIndex == numIntArgRegs: + contents += f"sp[{stackOffset}]" + stackOffset += 1 + else: + contents += f"x{intRegIndex}" + intRegIndex += 1 + elif arg == "Int64": + if intRegIndex == numIntArgRegs: + contents += f"sp[{stackOffset}]" + stackOffset += 1 + else: + contents += f"x{intRegIndex}" + intRegIndex += 1 + elif arg == "Float32": + if floatRegIndex == numFloatArgRegs: + contents += f"mozilla::BitwiseCast<float>(sp[{stackOffset}])" + stackOffset += 1 + else: + contents += f"s{floatRegIndex}" + floatRegIndex += 1 + elif arg == "Float64": + if floatRegIndex == numFloatArgRegs: + contents += f"mozilla::BitwiseCast<double>(sp[{stackOffset}])" + stackOffset += 1 + else: + contents += f"d{floatRegIndex}" + floatRegIndex += 1 + assert intRegIndex <= numIntArgRegs + assert floatRegIndex <= numFloatArgRegs + return contents + + +def arm64_simulator_dispatch(func_types): + contents = "" + for func_type in func_types: + args = arm64_args(func_type) + contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n" + contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n" + contents += f" auto ret = target({args});\\\n" + ret = func_type["ret"] + if ret == "General": + contents += " setGPR64Result(ret);\\\n" + elif ret == "Int32": + contents += " setGPR32Result(ret);\\\n" + elif ret == "Int64": + contents += " setGPR64Result(ret);\\\n" + elif ret == "Float32": + contents += " setFP32Result(ret);\\\n" + elif ret == "Float64": + contents += " setFP64Result(ret);\\\n" + contents += " break;\\\n" + contents += "}\\\n" + return contents + + +# Generate the LoongArch64 argument loading for a func type +def loongarch64_args(func_type): + # This must match ABIArgGenerator::next() in Assembler-loong64.cpp + contents = "" + numIntArgRegs = 8 + numFloatArgRegs = 8 + intRegIndex = 0 + floatRegIndex = 0 + stackOffset = 0 + for i, arg in enumerate(func_type["args"]): + if i != 0: + contents += ", " + + if arg == "General": + if intRegIndex == numIntArgRegs: + contents += f"sp_[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}_" + intRegIndex += 1 + elif arg == "Int32": + if intRegIndex == numIntArgRegs: + contents += f"I32(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"I32(a{intRegIndex}_)" + intRegIndex += 1 + elif arg == "Int64": + if intRegIndex == numIntArgRegs: + contents += f"sp_[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{intRegIndex}_" + intRegIndex += 1 + elif arg == "Float32": + if floatRegIndex == numFloatArgRegs: + contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"f{floatRegIndex}_s" + floatRegIndex += 1 + elif arg == "Float64": + if floatRegIndex == numFloatArgRegs: + contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"f{floatRegIndex}_d" + floatRegIndex += 1 + assert intRegIndex <= numIntArgRegs + assert floatRegIndex <= numFloatArgRegs + return contents + + +def loongarch64_simulator_dispatch(func_types): + contents = "" + for func_type in func_types: + args = loongarch64_args(func_type) + contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n" + contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n" + contents += f" auto ret = target({args});\\\n" + ret = func_type["ret"] + if ret == "General": + contents += " setCallResult(ret);\\\n" + elif ret == "Int32": + contents += " setCallResult(I64(ret));\\\n" + elif ret == "Int64": + contents += " setCallResult(ret);\\\n" + elif ret == "Float32": + contents += " setCallResultFloat(ret);\\\n" + elif ret == "Float64": + contents += " setCallResultDouble(ret);\\\n" + contents += " break;\\\n" + contents += "}\\\n" + return contents + + +# Generate the MIPS64 argument loading for a func type +def mips64_args(func_type): + # This must match ABIArgGenerator::next() in Assembler-mips64.cpp + contents = "" + numIntArgRegs = 8 + numFloatArgRegs = 8 + regIndex = 0 + stackOffset = 0 + for i, arg in enumerate(func_type["args"]): + if i != 0: + contents += ", " + + if arg == "General": + if regIndex == numIntArgRegs: + contents += f"sp_[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{regIndex}_" + regIndex += 1 + elif arg == "Int32": + if regIndex == numIntArgRegs: + contents += f"I32(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"I32(a{regIndex}_)" + regIndex += 1 + elif arg == "Int64": + if regIndex == numIntArgRegs: + contents += f"sp_[{stackOffset}]" + stackOffset += 1 + else: + contents += f"a{regIndex}_" + regIndex += 1 + elif arg == "Float32": + if regIndex == numFloatArgRegs: + contents += f"*mozilla::BitwiseCast<float*>(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"f{regIndex + 12}_s" + regIndex += 1 + elif arg == "Float64": + if regIndex == numFloatArgRegs: + contents += f"mozilla::BitwiseCast<double>(sp_[{stackOffset}])" + stackOffset += 1 + else: + contents += f"f{regIndex + 12}_d" + regIndex += 1 + assert regIndex <= numIntArgRegs + assert numIntArgRegs == numFloatArgRegs + return contents + + +def mips64_simulator_dispatch(func_types): + contents = "" + for func_type in func_types: + args = mips64_args(func_type) + contents += f"case js::jit::Args_{func_type_name(func_type)}: {{\\\n" + contents += f" auto target = reinterpret_cast<Prototype_{func_type_name(func_type)}>(nativeFn);\\\n" + contents += f" auto ret = target({args});\\\n" + ret = func_type["ret"] + if ret == "General": + contents += " setCallResult(ret);\\\n" + elif ret == "Int32": + contents += " setCallResult(I64(ret));\\\n" + elif ret == "Int64": + contents += " setCallResult(ret);\\\n" + elif ret == "Float32": + contents += " setCallResultFloat(ret);\\\n" + elif ret == "Float64": + contents += " setCallResultDouble(ret);\\\n" + contents += " break;\\\n" + contents += "}\\\n" + return contents + + +def main(c_out, yaml_path): + func_types = load_yaml(yaml_path) + + # Define the ABIFunctionType enum + contents = "#define ABI_FUNCTION_TYPE_ENUM \\\n" + for func_type in func_types: + name = "Args_" + func_type_name(func_type) + args = ", ".join(f"ABIType::{p}" for p in func_type["args"]) + ret = f"ABIType::{func_type['ret']}" + + contents += f" {name} = detail::MakeABIFunctionType({ret}, {{{args}}}),\\\n" + contents += "\n" + + # Define the prototypes of the types + contents += "#define ABI_FUNCTION_TYPE_SIM_PROTOTYPES \\\n" + for func_type in func_types: + name = "Prototype_" + func_type_name(func_type) + args = ", ".join(cpp_arg_type(p) for p in func_type["args"]) + ret = cpp_arg_type(func_type["ret"]) + + contents += f" typedef {ret} (*{name})({args});\\\n" + contents += "\n" + + contents += "#define ABI_FUNCTION_TYPE_ARM64_SIM_DISPATCH \\\n" + contents += arm64_simulator_dispatch(func_types) + contents += "\n" + + contents += "#define ABI_FUNCTION_TYPE_ARM32_SIM_DISPATCH \\\n" + contents += arm32_simulator_dispatch(func_types) + contents += "\n" + + contents += "#define ABI_FUNCTION_TYPE_LOONGARCH64_SIM_DISPATCH \\\n" + contents += loongarch64_simulator_dispatch(func_types) + contents += "\n" + + contents += "#define ABI_FUNCTION_TYPE_MIPS64_SIM_DISPATCH \\\n" + contents += mips64_simulator_dispatch(func_types) + contents += "\n" + + generate_header(c_out, "jit_ABIFunctionTypeGenerated_h", contents) |