summaryrefslogtreecommitdiffstats
path: root/js/src/jit/GenerateABIFunctionType.py
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/GenerateABIFunctionType.py')
-rw-r--r--js/src/jit/GenerateABIFunctionType.py483
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)