Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/jit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 15 kB image not shown  

Quelle  GenerateLIRFiles.py   Sprache: Python

 
# 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 io
from itertools import groupby
from operator import itemgetter

import buildconfig
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 = io.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",
}


# Generate the index expression for a BoxedValue operand.
#
# The expression has the form |num_operands + index * BOX_PIECES|, with zero
# terms being omitted.
def make_boxed_index(index, reg_operands):
    num_operands = len(reg_operands)

    expr = []
    if num_operands:
        expr.append(f"{num_operands}")
    if index:
        expr.append(f"{index} * BOX_PIECES")
    return " + ".join(expr) if expr else "0"


# Generate the index expression for an Int64 operand.
#
# The expression has the form
# |num_operands + num_value_operands * BOX_PIECES + index * INT64_PIECES|, with
# zero terms being omitted.
def make_int64_index(index, reg_operands, value_operands):
    num_operands = len(reg_operands)
    num_value_operands = len(value_operands)

    expr = []
    if num_operands:
        expr.append(f"{num_operands}")
    if num_value_operands:
        expr.append(f"{num_value_operands} * BOX_PIECES")
    if index:
        expr.append(f"{index} * INT64_PIECES")
    return " + ".join(expr) if expr else "0"


def gen_operands(operands, defer_init):
    # Group operands by operand type.
    sorted_operands = {
        k: [op for op, _ in v]
        for k, v in groupby(sorted(operands.items(), key=itemgetter(1)), itemgetter(1))
    }

    # Exactly three operand types are supported: WordSized, BoxedValue, and Int64.
    if len(sorted_operands) > 3:
        raise Exception("Invalid operand type: " + str(sorted_operands.keys()))

    reg_operands = sorted_operands.get("WordSized", [])
    value_operands = sorted_operands.get("BoxedValue", [])
    int64_operands = sorted_operands.get("Int64", [])

    # Operand index definitions.
    indices = []

    # Parameters for the class constructor.
    params = []

    # Initializer instructions for constructor body.
    initializers = []

    # Getter definitions.
    getters = []

    # Setter definitions.
    setters = []

    # Constructor parameters are generated in the order defined in the YAML file.
    if not defer_init:
        for operand, op_type in operands.items():
            params.append(f"const {operand_types[op_type]}& {operand}")

    # First initialize all word-sized operands.
    for index, operand in enumerate(reg_operands):
        cap_operand = operand[0].upper() + operand[1:]
        index_value = cap_operand + "Index"
        init_expr = f"setOperand({index_value}, {operand});"

        indices.append(f"static constexpr size_t {index_value} = {index};")
        if not defer_init:
            initializers.append(init_expr)
        else:
            setters.append(
                f"void set{cap_operand}(const LAllocation& {operand}) {{ {init_expr} }}"
            )
        getters.append(
            f"const LAllocation* {operand}() const {{ return getOperand({index_value}); }}"
        )

    # Next initialize all BoxedValue operands.
    for box_index, operand in enumerate(value_operands):
        cap_operand = operand[0].upper() + operand[1:]
        index_value = cap_operand + "Index"
        init_expr = f"setBoxOperand({index_value}, {operand});"

        indices.append(
            f"static constexpr size_t {index_value} = {make_boxed_index(box_index, reg_operands)};"
        )
        if not defer_init:
            initializers.append(init_expr)
        else:
            setters.append(
                f"void {cap_operand}(const LBoxAllocation& {operand}) {{ {init_expr} }}"
            )
        getters.append(
            f"LBoxAllocation {operand}() const {{ return getBoxOperand({index_value}); }}"
        )

    # Finally initialize all Int64 operands.
    for int64_index, operand in enumerate(int64_operands):
        cap_operand = operand[0].upper() + operand[1:]
        index_value = cap_operand + "Index"
        init_expr = f"setInt64Operand({index_value}, {operand});"

        indices.append(
            f"static constexpr size_t {index_value} = {make_int64_index(int64_index, reg_operands, value_operands)};"
        )
        if not defer_init:
            initializers.append(init_expr)
        else:
            setters.append(
                f"void set{cap_operand}(const LInt64Allocation& {operand}) {{ {init_expr} }}"
            )
        getters.append(
            f"LInt64Allocation {operand}() const {{ return getInt64Operand({index_value}); }}"
        )

    # Total number of operands.
    num_operands = f"{len(reg_operands)}"
    if value_operands:
        num_operands += f" + {len(value_operands)} * BOX_PIECES"
    if int64_operands:
        num_operands += f" + {len(int64_operands)} * INT64_PIECES"

    return (
        num_operands,
        indices,
        params,
        initializers,
        getters,
        setters,
    )


def gen_arguments(arguments):
    # Class member definitions.
    members = []

    # Parameters for the class constructor.
    params = []

    # Initializer instructions for the class constructor.
    initializers = []

    # Getter definitions.
    getters = []

    for arg_name in arguments:
        arg_type_sig = arguments[arg_name]

        members.append(f"{arg_type_sig} {arg_name}_;")
        params.append(f"{arg_type_sig} {arg_name}")
        initializers.append(f"{arg_name}_({arg_name})")
        getters.append(f"{arg_type_sig} {arg_name}() const {{ return {arg_name}_; }}")

    return (members, params, initializers, getters)


def gen_temps(num_temps, num_temps64, defer_init):
    # Parameters for the class constructor.
    params = []

    # Initializer instructions for constructor body.
    initializers = []

    # Getter definitions.
    getters = []

    # Setter definitions.
    setters = []

    for temp in range(num_temps):
        param_decl = f"const LDefinition& temp{temp}"
        init_expr = f"setTemp({temp}, temp{temp});"

        if not defer_init:
            params.append(param_decl)
            initializers.append(init_expr)
        else:
            initializers.append(f"setTemp({temp}, LDefinition::BogusTemp());")
            setters.append(f"void setTemp{temp}({param_decl}) {{ {init_expr} }}")
        getters.append(f"const LDefinition* temp{temp}() {{ return getTemp({temp}); }}")

    for int64_temp in range(num_temps64):
        temp = num_temps + int64_temp
        temp_index = f"{num_temps} + {int64_temp} * INT64_PIECES"
        param_decl = f"const LInt64Definition& temp{temp}"
        init_expr = f"setInt64Temp({temp_index}, temp{temp});"

        if not defer_init:
            params.append(param_decl)
            initializers.append(init_expr)
        else:
            initializers.append(f"setTemp({temp}, LInt64Definition::BogusTemp());")
            setters.append(f"void setTemp{temp}({param_decl}) {{ {init_expr} }}")
        getters.append(
            f"LInt64Definition temp{temp}() {{ return getInt64Temp({temp_index}); }}"
        )

    # Total number of temps.
    num_temps_total = f"{num_temps}"
    if num_temps64:
        num_temps_total += f" + {num_temps64} * INT64_PIECES"

    return (num_temps_total, params, initializers, getters, setters)


def gen_successors(successors):
    # Parameters for the class constructor.
    params = []

    # Initializer instructions for constructor body.
    initializers = []

    # Getter definitions.
    getters = []

    for index, successor in enumerate(successors or []):
        params.append(f"MBasicBlock* {successor}")
        initializers.append(f"setSuccessor({index}, {successor});")
        getters.append(
            f"MBasicBlock* {successor}() const {{ return getSuccessor({index}); }}"
        )

    return (params, initializers, getters)


def gen_lir_class(
    name,
    result_type,
    successors,
    operands,
    arguments,
    num_temps,
    num_temps64,
    call_instruction,
    mir_op,
    extra_name,
    defer_init,
):
    """Generates class definition for a single LIR opcode."""
    class_name = "L" + name

    (
        num_operands,
        oper_indices,
        oper_params,
        oper_initializers,
        oper_getters,
        oper_setters,
    ) = gen_operands(operands, defer_init)

    args_members, args_params, args_initializers, args_getters = gen_arguments(
        arguments
    )

    num_temps_total, temp_params, temp_initializers, temp_getters, temp_setters = (
        gen_temps(num_temps, num_temps64, defer_init)
    )

    succ_params, succ_initializers, succ_getters = gen_successors(successors)

    if successors is not None:
        if result_type:
            raise Exception("Control instructions don't return a result")
        num_defs = len(successors)
        parent_class = "LControlInstructionHelper"
    else:
        num_defs = result_types[result_type] if result_type else "0"
        parent_class = "LInstructionHelper"

    constructor_init = ""
    if call_instruction:
        constructor_init += "this->setIsCall();"

    mir_accessor = ""
    if mir_op:
        mir_name = name if mir_op is True else mir_op
        mir_accessor = f"M{mir_name}* mir() const {{ return mir_->to{mir_name}(); }};"

    extra_name_decl = ""
    if extra_name:
        extra_name_decl = "inline const char* extraName() const;"

    # Can be moved into the f-string when we use Python 3.12, see PEP 701.
    def nl(ws):
        return "\n" + ws

    code = f"""
class {class_name} : public {parent_class}<{num_defs}, {num_operands}, {num_temps_total}> {{
  {nl(" ").join(args_members)}

 public:
  LIR_HEADER({name})

  {nl(" ").join(oper_indices)}

  explicit {class_name}({", ".join(succ_params + oper_params + temp_params + args_params)}) : {parent_class}(classOpcode){", ".join([""] + args_initializers)} {{
    {constructor_init}
    {nl(" ").join(succ_initializers)}
    {nl(" ").join(oper_initializers)}
    {nl(" ").join(temp_initializers)}
  }}

  {nl(" ").join(succ_getters)}
  {nl(" ").join(oper_getters)}
  {nl(" ").join(oper_setters)}
  {nl(" ").join(temp_getters)}
  {nl(" ").join(temp_setters)}
  {nl(" ").join(args_getters)}
  {mir_accessor}
  {extra_name_decl}
}};
"""

    # Remove blank lines and add backslashes at line endings.
    return "\\\n".join(line for line in code.splitlines() if line.strip())


def mir_type_to_lir_type(mir_type):
    if mir_type == "Value":
        return "BoxedValue"
    return "WordSized"


def generate_lir_header(c_out, yaml_path, mir_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 result_type in result_types

            successors = op.get("successors"None)
            assert successors is None or isinstance(successors, list)

            operands = op.get("operands"or {}
            assert isinstance(operands, dict)

            arguments = op.get("arguments"or {}
            assert isinstance(arguments, dict)

            num_temps = op.get("num_temps", 0)
            assert isinstance(num_temps, int)

            num_temps64 = op.get("num_temps64", 0)
            assert isinstance(num_temps64, int)

            gen_boilerplate = op.get("gen_boilerplate"True)
            assert isinstance(gen_boilerplate, bool)

            call_instruction = op.get("call_instruction"None)
            assert isinstance(call_instruction, (type(None), bool))

            mir_op = op.get("mir_op"None)
            assert mir_op in (NoneTrueor isinstance(mir_op, str)

            extra_name = op.get("extra_name"False)
            assert isinstance(extra_name, bool)

            defer_init = op.get("defer_init"False)
            assert isinstance(defer_init, bool)

            lir_op_classes.append(
                gen_lir_class(
                    name,
                    result_type,
                    successors,
                    operands,
                    arguments,
                    num_temps,
                    num_temps64,
                    call_instruction,
                    mir_op,
                    extra_name,
                    defer_init,
                )
            )

        ops.append("_({})".format(name))

    # Generate LIR instructions for MIR instructions with 'generate_lir': true
    mir_data = load_yaml(mir_yaml_path)

    for op in mir_data:
        name = op["name"]

        generate_lir = op.get("generate_lir"False)
        assert isinstance(generate_lir, bool)

        if generate_lir:
            result_type = op.get("result_type"None)
            assert isinstance(result_type, (type(None), str))

            if result_type:
                result_type = mir_type_to_lir_type(result_type)
                assert result_type in result_types

            successors = None

            operands_raw = op.get("operands", {})
            assert isinstance(operands_raw, dict)

            operands = {op: mir_type_to_lir_type(ty) for op, ty in operands_raw.items()}

            arguments = {}

            num_temps = op.get("lir_temps", 0)
            assert isinstance(num_temps, int)

            num_temps64 = op.get("lir_temps64", 0)
            assert isinstance(num_temps64, int)

            call_instruction = op.get("possibly_calls"None)
            assert isinstance(call_instruction, (type(None), bool))

            mir_op = None

            extra_name = False

            defer_init = False

            lir_op_classes.append(
                gen_lir_class(
                    name,
                    result_type,
                    successors,
                    operands,
                    arguments,
                    num_temps,
                    num_temps64,
                    call_instruction,
                    mir_op,
                    extra_name,
                    defer_init,
                )
            )

            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)

Messung V0.5
C=93 H=97 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.