Skip to content

Passes

passes

ModulePassT = TypeVar('ModulePassT', bound='ModulePass') module-attribute

ModulePass dataclass

Bases: ArgSpecConvertible

A Pass is a named rewrite pass over an IR module that can accept arguments.

All passes are expected to leave the IR in a valid state after application, meaning that a call to .verify() succeeds on the whole module. In turn, all passes can expect that the IR they are applied to is in a valid state. It is not required that the IR verifies at any point while the pass is being applied.

In order to make a pass accept arguments, it must be a dataclass. Furthermore, only the following types are supported as argument types:

Base types: int | float | bool | string N-tuples of base types: tuple[int, ...], tuple[int|float, ...], tuple[int, ...] | tuple[float, ...] Top-level optional: ... | None

Pass arguments on the CLI are formatted as follows:

CLI arg Mapped to class field ------------------------- ------------------------------ my-pass{arg-1=1} arg_1: int = 1 my-pass{arg-1} arg_1: int | None = None my-pass{arg-1=1,2,3} arg_1: tuple[int, ...] = (1, 2, 3) my-pass{arg-1=true} arg_1: bool | None = True

Source code in xdsl/passes.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
@dataclass(frozen=True)
class ModulePass(ArgSpecConvertible):
    """
    A Pass is a named rewrite pass over an IR module that can accept arguments.

    All passes are expected to leave the IR in a valid state *after* application,
    meaning that a call to .verify() succeeds on the whole module. In turn, all
    passes can expect that the IR they are applied to is in a valid state. It
    is not required that the IR verifies at any point while the pass is being
    applied.

    In order to make a pass accept arguments, it must be a dataclass. Furthermore,
    only the following types are supported as argument types:

    Base types:                int | float | bool | string
    N-tuples of base types:
        tuple[int, ...], tuple[int|float, ...], tuple[int, ...] | tuple[float, ...]
    Top-level optional:        ... | None

    Pass arguments on the CLI are formatted as follows:

    CLI arg                             Mapped to class field
    -------------------------           ------------------------------
    my-pass{arg-1=1}                    arg_1: int             = 1
    my-pass{arg-1}                      arg_1: int | None      = None
    my-pass{arg-1=1,2,3}                arg_1: tuple[int, ...] = (1, 2, 3)
    my-pass{arg-1=true}                 arg_1: bool | None     = True
    """

    name: ClassVar[str]

    @abstractmethod
    def apply(self, ctx: Context, op: builtin.ModuleOp) -> None: ...

    def apply_to_clone(
        self, ctx: Context, op: builtin.ModuleOp
    ) -> tuple[Context, builtin.ModuleOp]:
        """
        Creates deep copies of the module and the context, and returns the result of
        calling `apply` on them.
        """
        ctx = ctx.clone()
        op = op.clone()
        self.apply(ctx, op)
        return ctx, op

    @classmethod
    def from_pass_spec(cls, spec: ArgSpec) -> Self:
        """Alias for ``from_spec`` for backward compatibility."""
        return cls.from_spec(spec)

    def pipeline_pass_spec(self, *, include_default: bool = False) -> ArgSpec:
        """Alias for ``spec`` for backward compatibility."""
        return self.spec(include_default=include_default)

    @classmethod
    def schedule_space(
        cls, ctx: Context, module_op: builtin.ModuleOp
    ) -> tuple[Self, ...]:
        """
        Returns a tuple of `Self` that can be applied to rewrite the given module with
        the given context without error.
        The default implementation attempts to construct an instance with no parameters,
        and run it on the module_op; if the module_op is mutated then the pass instance
        is returned.
        Parametrizable passes should override this implementation to provide a full
        schedule space of transformations.
        """
        try:
            pass_instance = cls()
            _, cloned_module = pass_instance.apply_to_clone(ctx, module_op)
            if module_op.is_structurally_equivalent(cloned_module):
                return ()
        except Exception:
            return ()
        return (pass_instance,)

name: str class-attribute

__init__() -> None

apply(ctx: Context, op: builtin.ModuleOp) -> None abstractmethod

Source code in xdsl/passes.py
57
58
@abstractmethod
def apply(self, ctx: Context, op: builtin.ModuleOp) -> None: ...

apply_to_clone(ctx: Context, op: builtin.ModuleOp) -> tuple[Context, builtin.ModuleOp]

Creates deep copies of the module and the context, and returns the result of calling apply on them.

Source code in xdsl/passes.py
60
61
62
63
64
65
66
67
68
69
70
def apply_to_clone(
    self, ctx: Context, op: builtin.ModuleOp
) -> tuple[Context, builtin.ModuleOp]:
    """
    Creates deep copies of the module and the context, and returns the result of
    calling `apply` on them.
    """
    ctx = ctx.clone()
    op = op.clone()
    self.apply(ctx, op)
    return ctx, op

from_pass_spec(spec: ArgSpec) -> Self classmethod

Alias for from_spec for backward compatibility.

Source code in xdsl/passes.py
72
73
74
75
@classmethod
def from_pass_spec(cls, spec: ArgSpec) -> Self:
    """Alias for ``from_spec`` for backward compatibility."""
    return cls.from_spec(spec)

pipeline_pass_spec(*, include_default: bool = False) -> ArgSpec

Alias for spec for backward compatibility.

Source code in xdsl/passes.py
77
78
79
def pipeline_pass_spec(self, *, include_default: bool = False) -> ArgSpec:
    """Alias for ``spec`` for backward compatibility."""
    return self.spec(include_default=include_default)

schedule_space(ctx: Context, module_op: builtin.ModuleOp) -> tuple[Self, ...] classmethod

Returns a tuple of Self that can be applied to rewrite the given module with the given context without error. The default implementation attempts to construct an instance with no parameters, and run it on the module_op; if the module_op is mutated then the pass instance is returned. Parametrizable passes should override this implementation to provide a full schedule space of transformations.

Source code in xdsl/passes.py
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
@classmethod
def schedule_space(
    cls, ctx: Context, module_op: builtin.ModuleOp
) -> tuple[Self, ...]:
    """
    Returns a tuple of `Self` that can be applied to rewrite the given module with
    the given context without error.
    The default implementation attempts to construct an instance with no parameters,
    and run it on the module_op; if the module_op is mutated then the pass instance
    is returned.
    Parametrizable passes should override this implementation to provide a full
    schedule space of transformations.
    """
    try:
        pass_instance = cls()
        _, cloned_module = pass_instance.apply_to_clone(ctx, module_op)
        if module_op.is_structurally_equivalent(cloned_module):
            return ()
    except Exception:
        return ()
    return (pass_instance,)

PassOptionInfo

Bases: NamedTuple

The name, expected type, and default value for one option of a module pass.

Source code in xdsl/passes.py
104
105
106
107
108
109
class PassOptionInfo(NamedTuple):
    """The name, expected type, and default value for one option of a module pass."""

    name: str
    expected_type: str
    default_value: str | None = None

name: str instance-attribute

expected_type: str instance-attribute

default_value: str | None = None class-attribute instance-attribute

PassPipeline dataclass

A representation of a pass pipeline, with an optional callback to be executed between each of the passes.

Source code in xdsl/passes.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
@dataclass(frozen=True)
class PassPipeline:
    """
    A representation of a pass pipeline, with an optional callback to be executed
    between each of the passes.
    """

    passes: tuple[ModulePass, ...]
    """
    These will be executed sequentially during the execution of the pipeline.
    """
    callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None] | None = field(
        default=None
    )
    """
    Function called in between every pass, taking the pass that just ran, the module,
    and the next pass.
    """

    def apply(self, ctx: Context, op: builtin.ModuleOp) -> None:
        if not self.passes:
            # Early exit to avoid fetching a non-existing last pass.
            return
        callback = self.callback

        for prev, next in zip(self.passes[:-1], self.passes[1:]):
            prev.apply(ctx, op)
            if callback is not None:
                callback(prev, op, next)

        self.passes[-1].apply(ctx, op)

    @staticmethod
    def parse_spec(
        available_passes: dict[str, Callable[[], type[ModulePass]]],
        spec: str,
        callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None]
        | None = None,
    ) -> PassPipeline:
        specs = tuple(parse_pipeline(spec))
        unrecognised_passes = tuple(
            p.name for p in specs if p.name not in available_passes
        )
        if unrecognised_passes:
            raise ValueError(f"Unrecognized passes: {list(unrecognised_passes)}")

        passes = tuple(available_passes[p.name]().from_pass_spec(p) for p in specs)

        return PassPipeline(passes, callback)

passes: tuple[ModulePass, ...] instance-attribute

These will be executed sequentially during the execution of the pipeline.

callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None] | None = field(default=None) class-attribute instance-attribute

Function called in between every pass, taking the pass that just ran, the module, and the next pass.

__init__(passes: tuple[ModulePass, ...], callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None] | None = None) -> None

apply(ctx: Context, op: builtin.ModuleOp) -> None

Source code in xdsl/passes.py
149
150
151
152
153
154
155
156
157
158
159
160
def apply(self, ctx: Context, op: builtin.ModuleOp) -> None:
    if not self.passes:
        # Early exit to avoid fetching a non-existing last pass.
        return
    callback = self.callback

    for prev, next in zip(self.passes[:-1], self.passes[1:]):
        prev.apply(ctx, op)
        if callback is not None:
            callback(prev, op, next)

    self.passes[-1].apply(ctx, op)

parse_spec(available_passes: dict[str, Callable[[], type[ModulePass]]], spec: str, callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None] | None = None) -> PassPipeline staticmethod

Source code in xdsl/passes.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
@staticmethod
def parse_spec(
    available_passes: dict[str, Callable[[], type[ModulePass]]],
    spec: str,
    callback: Callable[[ModulePass, builtin.ModuleOp, ModulePass], None]
    | None = None,
) -> PassPipeline:
    specs = tuple(parse_pipeline(spec))
    unrecognised_passes = tuple(
        p.name for p in specs if p.name not in available_passes
    )
    if unrecognised_passes:
        raise ValueError(f"Unrecognized passes: {list(unrecognised_passes)}")

    passes = tuple(available_passes[p.name]().from_pass_spec(p) for p in specs)

    return PassPipeline(passes, callback)

get_pass_option_infos(arg: type[ModulePassT]) -> tuple[PassOptionInfo, ...]

Returns the expected argument names, types, and optional expected values for options for the given pass.

Source code in xdsl/passes.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def get_pass_option_infos(
    arg: type[ModulePassT],
) -> tuple[PassOptionInfo, ...]:
    """
    Returns the expected argument names, types, and optional expected values for options
    for the given pass.
    """

    return tuple(
        PassOptionInfo(
            field.name,
            type_repr(field.type),
            str(getattr(arg, field.name)).lower() if hasattr(arg, field.name) else None,
        )
        for field in dataclasses.fields(arg)
    )