Skip to content

Symbol table

symbol_table

Helper methods and classes to reason about operations that refer to other operations.

Visibility

Bases: StrEnum

An enumeration detailing the different visibility types that a symbol may have.

Source code in xdsl/utils/symbol_table.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Visibility(StrEnum):
    """
    An enumeration detailing the different visibility types that a symbol may have.
    """

    PUBLIC = "public"
    """
    The symbol is public and may be referenced anywhere internal or external to the
    visible references in the IR.
    """

    PRIVATE = "private"
    """
    The symbol is private and may only be referenced by SymbolRefAttrs local to the
    operations within the current symbol table.
    """

    NESTED = "nested"
    """
    The symbol is visible to the current IR, which may include operations in symbol
    tables above the one that owns the current symbol.
    `nested` visibility allows for referencing a symbol outside of its current symbol
    table, while retaining the ability to observe all uses.
    """

PUBLIC = 'public' class-attribute instance-attribute

The symbol is public and may be referenced anywhere internal or external to the visible references in the IR.

PRIVATE = 'private' class-attribute instance-attribute

The symbol is private and may only be referenced by SymbolRefAttrs local to the operations within the current symbol table.

NESTED = 'nested' class-attribute instance-attribute

The symbol is visible to the current IR, which may include operations in symbol tables above the one that owns the current symbol. nested visibility allows for referencing a symbol outside of its current symbol table, while retaining the ability to observe all uses.

SymbolUse

Bases: NamedTuple

Source code in xdsl/utils/symbol_table.py
43
44
45
46
47
class SymbolUse(NamedTuple):
    owner: Operation
    """The operation that this access is held by."""
    symbol_ref: SymbolRefAttr
    """The symbol reference that this use represents."""

owner: Operation instance-attribute

The operation that this access is held by.

symbol_ref: SymbolRefAttr instance-attribute

The symbol reference that this use represents.

SymbolTable

This class allows for representing and managing the symbol table used by operations with the 'SymbolTable' trait. Inserting into and erasing from this SymbolTable will also insert and erase from the Operation given to it at construction.

Source code in xdsl/utils/symbol_table.py
 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
class SymbolTable:
    """
    This class allows for representing and managing the symbol table used by operations
    with the 'SymbolTable' trait.
    Inserting into and erasing from this SymbolTable will also insert and erase from the
    Operation given to it at construction.
    """

    _symbol_table_op: Operation
    _symbol_table: dict[str, Operation]
    """
    This is a mapping from a name to the symbol with that name.
    """
    _uniquing_counter: int
    """
    This is used when name conflicts are detected.
    """

    def __init__(self, symbol_table_op: Operation):
        assert symbol_table_op.get_trait(traits.SymbolTable) is not None, (
            "Expected operation to have SymbolTable trait"
        )
        self._symbol_table_op = symbol_table_op
        self._symbol_table = {}
        self._uniquing_counter = 0

        block = self._symbol_table_op.regions[0].blocks[0]
        for op in block.ops:
            if (name := get_name_if_symbol(op)) is not None:
                self._symbol_table[name] = op

    def lookup(self, name: str | StringAttr) -> Operation | None:
        """
        Look up a symbol with the specified name, returning `None` if no such name
        exists.
        Names never include the `@` on them.
        """
        name = name.data if isinstance(name, StringAttr) else name
        return self._symbol_table.get(name)

    def remove(self, op: Operation) -> None:
        """Remove the given symbol from the table, without deleting it."""
        if (name := get_name_if_symbol(op)) is None:
            raise ValueError("Expected valid 'name' attribute")

        if self._symbol_table.pop(name, None) is None:
            raise ValueError(
                "Expected this operation to be inside of the operation with this SymbolTable"
            )

    def erase(self, op: Operation) -> None:
        """Erase the given symbol from the table and delete the operation."""
        self.remove(op)
        op.detach()
        op.erase()

    def insert(self, symbol: Operation, insertion_point: InsertPoint) -> StringAttr:
        """
        Insert a new symbol into the table, and rename it as necessary to avoid
        collisions. Also insert at the specified location in the body of the associated
        operation if it is not already there. It is asserted that the symbol is not
        inside another operation. Return the name of the symbol after insertion as
        attribute.
        """
        raise NotImplementedError

    def rename(
        self, from_op: Operation | StringAttr, to_name: StringAttr | str
    ) -> None:
        """
        Renames the given op or the op referred to by the given name to the given new
        name and updates the symbol table and all usages of the symbol accordingly.
        Fails if the updating of the usages fails.
        """
        # TODO: update doc string once failure mechanism is implemented
        raise NotImplementedError

    def rename_to_unique(
        self, from_op: Operation | StringAttr, others: Sequence[SymbolTable]
    ) -> StringAttr | None:
        """
        Renames the given op or the op referred to by the given name to the given new
        name that is unique within this and the provided other symbol tables and
        updates the symbol table and all usages of the symbol accordingly.
        Returns the new name or `None` if the renaming fails.
        """
        raise NotImplementedError

    # Symbol Utilities

    @staticmethod
    def get_symbol_name(symbol: Operation) -> StringAttr | None:
        """
        Returns the name of the given symbol operation, or `None` if no symbol is
        present.
        """
        raise NotImplementedError

    @staticmethod
    def set_symbol_name(symbol: Operation, name: StringAttr | str) -> None:
        """Sets the name of the given symbol operation."""
        raise NotImplementedError

    @staticmethod
    def get_symbol_visibility(symbol: Operation) -> Visibility:
        """Returns the visibility of the given symbol operation."""
        visibility = symbol.get_attr_or_prop("sym_visibility")
        if visibility is None:
            return Visibility.PUBLIC
        if not isinstance(visibility, StringAttr):
            raise ValueError("Expected 'sym_visibility' to be a StringAttr")
        return Visibility(visibility.data)

    @staticmethod
    def set_symbol_visibility(symbol: Operation, vis: Visibility) -> None:
        """Sets the visibility of the given symbol operation."""
        raise NotImplementedError

    @staticmethod
    def get_nearest_symbol_table(from_op: Operation) -> Operation | None:
        """
        Returns the nearest symbol table from a given operation `from`.
        Returns `None` if no valid parent symbol table could be found.
        """
        op: Operation | None = from_op
        while op is not None:
            if op.has_trait(traits.SymbolTable, value_if_unregistered=False):
                return op
            op = op.parent_op()
        return None

    @staticmethod
    def walk_symbol_tables(
        op: Operation, all_sym_uses_visible: bool
    ) -> Iterator[Operation]:
        """
        Walks all symbol table operations nested within, and including, `op`.
        For each symbol table operation, the provided callback is invoked with the op
        and a boolean signifying if the symbols within that symbol table can be
        treated as if all uses within the IR are visible to the caller.
        `all_sym_uses_visible` identifies whether all of the symbol uses of symbols
        within `op` are visible.
        """
        raise NotImplementedError

    @overload
    @staticmethod
    def lookup_symbol_in(
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: Literal[True],
    ) -> list[Operation] | None: ...

    @overload
    @staticmethod
    def lookup_symbol_in(
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: Literal[False] = False,
    ) -> Operation | None: ...

    @staticmethod
    def lookup_symbol_in(
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: bool = False,
    ) -> list[Operation] | Operation | None:
        """
        Returns the operation registered with the given symbol name with the regions of
        `op`.
        `op` is required to be an operation with the 'xdsl.traits.SymbolTable' trait.
        If `all_symbols` is `True`, returns all symbols referenced by the symbol.
        """
        assert op.get_trait(traits.SymbolTable) is not None, (
            "Expected operation to have SymbolTable trait"
        )
        if isinstance(symbol, str | StringAttr):
            symbol_op = _lookup_symbol_in_direct_children(op, symbol)
            if all_symbols:
                return [symbol_op] if symbol_op is not None else None
            return symbol_op

        symbols = _lookup_symbol_ref_in(op, symbol, _lookup_symbol_in_direct_children)
        if symbols is None:
            return None
        return symbols if all_symbols else symbols[-1]

    @staticmethod
    def lookup_nearest_symbol_from(
        from_op: Operation, symbol: StringAttr | SymbolRefAttr | str
    ) -> Operation | None:
        """
        Returns the operation registered with the given symbol name within the closest
        parent operation of, or including, `from_op` with the
        [`SymbolTable`][xdsl.traits.SymbolTable] trait.
        Returns `None` if no valid symbol was found.
        """
        symbol_table_op = SymbolTable.get_nearest_symbol_table(from_op)
        if symbol_table_op is None:
            return None
        return SymbolTable.lookup_symbol_in(symbol_table_op, symbol)

    @staticmethod
    def get_symbol_uses(
        from_op: Operation | Region, *, symbol: StringAttr | Operation | None = None
    ) -> Sequence[SymbolUse]:
        """
        Get the symbol uses nested within `from_op` for the given `symbol`, or all the
        uses if `symbol` is `None`.
        This does not traverse into any nested symbol tables.
        This function returns `None` if there are any unknown operations that may
        potentially be symbol tables.
        """
        raise NotImplementedError

    @staticmethod
    def symbol_known_use_empty(
        symbol: Operation | StringAttr, from_op: Operation | Region
    ) -> bool:
        """
        Return if the given symbol is known to have no uses that are nested within the
        given operation 'from'.
        This does not traverse into any nested symbol tables.
        This function will also return false if there are any unknown operations that
        may potentially be symbol tables.
        This doesn't necessarily mean that there are no uses, we just can't
        conservatively prove it.
        """
        raise NotImplementedError

    @staticmethod
    def replace_all_symbol_uses(
        old_symbol: StringAttr | Operation,
        new_symbol: StringAttr,
        from_op: Operation | Region,
    ) -> bool:
        """
        Attempt to replace all uses of the given symbol `old_symbol` with the provided
        symbol `new_symbol` that are nested within the given operation `from_op`.
        This does not traverse into any nested symbol tables.
        If there are any unknown operations that may potentially be symbol tables, no
        uses are replaced and `False` is returned.
        """
        raise NotImplementedError

__init__(symbol_table_op: Operation)

Source code in xdsl/utils/symbol_table.py
76
77
78
79
80
81
82
83
84
85
86
87
def __init__(self, symbol_table_op: Operation):
    assert symbol_table_op.get_trait(traits.SymbolTable) is not None, (
        "Expected operation to have SymbolTable trait"
    )
    self._symbol_table_op = symbol_table_op
    self._symbol_table = {}
    self._uniquing_counter = 0

    block = self._symbol_table_op.regions[0].blocks[0]
    for op in block.ops:
        if (name := get_name_if_symbol(op)) is not None:
            self._symbol_table[name] = op

lookup(name: str | StringAttr) -> Operation | None

Look up a symbol with the specified name, returning None if no such name exists. Names never include the @ on them.

Source code in xdsl/utils/symbol_table.py
89
90
91
92
93
94
95
96
def lookup(self, name: str | StringAttr) -> Operation | None:
    """
    Look up a symbol with the specified name, returning `None` if no such name
    exists.
    Names never include the `@` on them.
    """
    name = name.data if isinstance(name, StringAttr) else name
    return self._symbol_table.get(name)

remove(op: Operation) -> None

Remove the given symbol from the table, without deleting it.

Source code in xdsl/utils/symbol_table.py
 98
 99
100
101
102
103
104
105
106
def remove(self, op: Operation) -> None:
    """Remove the given symbol from the table, without deleting it."""
    if (name := get_name_if_symbol(op)) is None:
        raise ValueError("Expected valid 'name' attribute")

    if self._symbol_table.pop(name, None) is None:
        raise ValueError(
            "Expected this operation to be inside of the operation with this SymbolTable"
        )

erase(op: Operation) -> None

Erase the given symbol from the table and delete the operation.

Source code in xdsl/utils/symbol_table.py
108
109
110
111
112
def erase(self, op: Operation) -> None:
    """Erase the given symbol from the table and delete the operation."""
    self.remove(op)
    op.detach()
    op.erase()

insert(symbol: Operation, insertion_point: InsertPoint) -> StringAttr

Insert a new symbol into the table, and rename it as necessary to avoid collisions. Also insert at the specified location in the body of the associated operation if it is not already there. It is asserted that the symbol is not inside another operation. Return the name of the symbol after insertion as attribute.

Source code in xdsl/utils/symbol_table.py
114
115
116
117
118
119
120
121
122
def insert(self, symbol: Operation, insertion_point: InsertPoint) -> StringAttr:
    """
    Insert a new symbol into the table, and rename it as necessary to avoid
    collisions. Also insert at the specified location in the body of the associated
    operation if it is not already there. It is asserted that the symbol is not
    inside another operation. Return the name of the symbol after insertion as
    attribute.
    """
    raise NotImplementedError

rename(from_op: Operation | StringAttr, to_name: StringAttr | str) -> None

Renames the given op or the op referred to by the given name to the given new name and updates the symbol table and all usages of the symbol accordingly. Fails if the updating of the usages fails.

Source code in xdsl/utils/symbol_table.py
124
125
126
127
128
129
130
131
132
133
def rename(
    self, from_op: Operation | StringAttr, to_name: StringAttr | str
) -> None:
    """
    Renames the given op or the op referred to by the given name to the given new
    name and updates the symbol table and all usages of the symbol accordingly.
    Fails if the updating of the usages fails.
    """
    # TODO: update doc string once failure mechanism is implemented
    raise NotImplementedError

rename_to_unique(from_op: Operation | StringAttr, others: Sequence[SymbolTable]) -> StringAttr | None

Renames the given op or the op referred to by the given name to the given new name that is unique within this and the provided other symbol tables and updates the symbol table and all usages of the symbol accordingly. Returns the new name or None if the renaming fails.

Source code in xdsl/utils/symbol_table.py
135
136
137
138
139
140
141
142
143
144
def rename_to_unique(
    self, from_op: Operation | StringAttr, others: Sequence[SymbolTable]
) -> StringAttr | None:
    """
    Renames the given op or the op referred to by the given name to the given new
    name that is unique within this and the provided other symbol tables and
    updates the symbol table and all usages of the symbol accordingly.
    Returns the new name or `None` if the renaming fails.
    """
    raise NotImplementedError

get_symbol_name(symbol: Operation) -> StringAttr | None staticmethod

Returns the name of the given symbol operation, or None if no symbol is present.

Source code in xdsl/utils/symbol_table.py
148
149
150
151
152
153
154
@staticmethod
def get_symbol_name(symbol: Operation) -> StringAttr | None:
    """
    Returns the name of the given symbol operation, or `None` if no symbol is
    present.
    """
    raise NotImplementedError

set_symbol_name(symbol: Operation, name: StringAttr | str) -> None staticmethod

Sets the name of the given symbol operation.

Source code in xdsl/utils/symbol_table.py
156
157
158
159
@staticmethod
def set_symbol_name(symbol: Operation, name: StringAttr | str) -> None:
    """Sets the name of the given symbol operation."""
    raise NotImplementedError

get_symbol_visibility(symbol: Operation) -> Visibility staticmethod

Returns the visibility of the given symbol operation.

Source code in xdsl/utils/symbol_table.py
161
162
163
164
165
166
167
168
169
@staticmethod
def get_symbol_visibility(symbol: Operation) -> Visibility:
    """Returns the visibility of the given symbol operation."""
    visibility = symbol.get_attr_or_prop("sym_visibility")
    if visibility is None:
        return Visibility.PUBLIC
    if not isinstance(visibility, StringAttr):
        raise ValueError("Expected 'sym_visibility' to be a StringAttr")
    return Visibility(visibility.data)

set_symbol_visibility(symbol: Operation, vis: Visibility) -> None staticmethod

Sets the visibility of the given symbol operation.

Source code in xdsl/utils/symbol_table.py
171
172
173
174
@staticmethod
def set_symbol_visibility(symbol: Operation, vis: Visibility) -> None:
    """Sets the visibility of the given symbol operation."""
    raise NotImplementedError

get_nearest_symbol_table(from_op: Operation) -> Operation | None staticmethod

Returns the nearest symbol table from a given operation from. Returns None if no valid parent symbol table could be found.

Source code in xdsl/utils/symbol_table.py
176
177
178
179
180
181
182
183
184
185
186
187
@staticmethod
def get_nearest_symbol_table(from_op: Operation) -> Operation | None:
    """
    Returns the nearest symbol table from a given operation `from`.
    Returns `None` if no valid parent symbol table could be found.
    """
    op: Operation | None = from_op
    while op is not None:
        if op.has_trait(traits.SymbolTable, value_if_unregistered=False):
            return op
        op = op.parent_op()
    return None

walk_symbol_tables(op: Operation, all_sym_uses_visible: bool) -> Iterator[Operation] staticmethod

Walks all symbol table operations nested within, and including, op. For each symbol table operation, the provided callback is invoked with the op and a boolean signifying if the symbols within that symbol table can be treated as if all uses within the IR are visible to the caller. all_sym_uses_visible identifies whether all of the symbol uses of symbols within op are visible.

Source code in xdsl/utils/symbol_table.py
189
190
191
192
193
194
195
196
197
198
199
200
201
@staticmethod
def walk_symbol_tables(
    op: Operation, all_sym_uses_visible: bool
) -> Iterator[Operation]:
    """
    Walks all symbol table operations nested within, and including, `op`.
    For each symbol table operation, the provided callback is invoked with the op
    and a boolean signifying if the symbols within that symbol table can be
    treated as if all uses within the IR are visible to the caller.
    `all_sym_uses_visible` identifies whether all of the symbol uses of symbols
    within `op` are visible.
    """
    raise NotImplementedError

lookup_symbol_in(op: Operation, symbol: StringAttr | SymbolRefAttr | str, *, all_symbols: bool = False) -> list[Operation] | Operation | None staticmethod

lookup_symbol_in(
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: Literal[True],
) -> list[Operation] | None
lookup_symbol_in(
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: Literal[False] = False,
) -> Operation | None

Returns the operation registered with the given symbol name with the regions of op. op is required to be an operation with the 'xdsl.traits.SymbolTable' trait. If all_symbols is True, returns all symbols referenced by the symbol.

Source code in xdsl/utils/symbol_table.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
@staticmethod
def lookup_symbol_in(
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: bool = False,
) -> list[Operation] | Operation | None:
    """
    Returns the operation registered with the given symbol name with the regions of
    `op`.
    `op` is required to be an operation with the 'xdsl.traits.SymbolTable' trait.
    If `all_symbols` is `True`, returns all symbols referenced by the symbol.
    """
    assert op.get_trait(traits.SymbolTable) is not None, (
        "Expected operation to have SymbolTable trait"
    )
    if isinstance(symbol, str | StringAttr):
        symbol_op = _lookup_symbol_in_direct_children(op, symbol)
        if all_symbols:
            return [symbol_op] if symbol_op is not None else None
        return symbol_op

    symbols = _lookup_symbol_ref_in(op, symbol, _lookup_symbol_in_direct_children)
    if symbols is None:
        return None
    return symbols if all_symbols else symbols[-1]

lookup_nearest_symbol_from(from_op: Operation, symbol: StringAttr | SymbolRefAttr | str) -> Operation | None staticmethod

Returns the operation registered with the given symbol name within the closest parent operation of, or including, from_op with the SymbolTable trait. Returns None if no valid symbol was found.

Source code in xdsl/utils/symbol_table.py
248
249
250
251
252
253
254
255
256
257
258
259
260
261
@staticmethod
def lookup_nearest_symbol_from(
    from_op: Operation, symbol: StringAttr | SymbolRefAttr | str
) -> Operation | None:
    """
    Returns the operation registered with the given symbol name within the closest
    parent operation of, or including, `from_op` with the
    [`SymbolTable`][xdsl.traits.SymbolTable] trait.
    Returns `None` if no valid symbol was found.
    """
    symbol_table_op = SymbolTable.get_nearest_symbol_table(from_op)
    if symbol_table_op is None:
        return None
    return SymbolTable.lookup_symbol_in(symbol_table_op, symbol)

get_symbol_uses(from_op: Operation | Region, *, symbol: StringAttr | Operation | None = None) -> Sequence[SymbolUse] staticmethod

Get the symbol uses nested within from_op for the given symbol, or all the uses if symbol is None. This does not traverse into any nested symbol tables. This function returns None if there are any unknown operations that may potentially be symbol tables.

Source code in xdsl/utils/symbol_table.py
263
264
265
266
267
268
269
270
271
272
273
274
@staticmethod
def get_symbol_uses(
    from_op: Operation | Region, *, symbol: StringAttr | Operation | None = None
) -> Sequence[SymbolUse]:
    """
    Get the symbol uses nested within `from_op` for the given `symbol`, or all the
    uses if `symbol` is `None`.
    This does not traverse into any nested symbol tables.
    This function returns `None` if there are any unknown operations that may
    potentially be symbol tables.
    """
    raise NotImplementedError

symbol_known_use_empty(symbol: Operation | StringAttr, from_op: Operation | Region) -> bool staticmethod

Return if the given symbol is known to have no uses that are nested within the given operation 'from'. This does not traverse into any nested symbol tables. This function will also return false if there are any unknown operations that may potentially be symbol tables. This doesn't necessarily mean that there are no uses, we just can't conservatively prove it.

Source code in xdsl/utils/symbol_table.py
276
277
278
279
280
281
282
283
284
285
286
287
288
289
@staticmethod
def symbol_known_use_empty(
    symbol: Operation | StringAttr, from_op: Operation | Region
) -> bool:
    """
    Return if the given symbol is known to have no uses that are nested within the
    given operation 'from'.
    This does not traverse into any nested symbol tables.
    This function will also return false if there are any unknown operations that
    may potentially be symbol tables.
    This doesn't necessarily mean that there are no uses, we just can't
    conservatively prove it.
    """
    raise NotImplementedError

replace_all_symbol_uses(old_symbol: StringAttr | Operation, new_symbol: StringAttr, from_op: Operation | Region) -> bool staticmethod

Attempt to replace all uses of the given symbol old_symbol with the provided symbol new_symbol that are nested within the given operation from_op. This does not traverse into any nested symbol tables. If there are any unknown operations that may potentially be symbol tables, no uses are replaced and False is returned.

Source code in xdsl/utils/symbol_table.py
291
292
293
294
295
296
297
298
299
300
301
302
303
304
@staticmethod
def replace_all_symbol_uses(
    old_symbol: StringAttr | Operation,
    new_symbol: StringAttr,
    from_op: Operation | Region,
) -> bool:
    """
    Attempt to replace all uses of the given symbol `old_symbol` with the provided
    symbol `new_symbol` that are nested within the given operation `from_op`.
    This does not traverse into any nested symbol tables.
    If there are any unknown operations that may potentially be symbol tables, no
    uses are replaced and `False` is returned.
    """
    raise NotImplementedError

SymbolTableCollection

This class represents a collection of SymbolTables. It simplifies certain algorithms that run recursively on nested symbol tables. Symbol tables are constructed lazily to reduce the upfront cost of constructing unnecessary tables.

Source code in xdsl/utils/symbol_table.py
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
class SymbolTableCollection:
    """
    This class represents a collection of `SymbolTable`s.
    It simplifies certain algorithms that run recursively on nested symbol tables.
    Symbol tables are constructed lazily to reduce the upfront cost of constructing
    unnecessary tables.
    """

    _symbol_tables: dict[Operation, SymbolTable]

    def __init__(self) -> None:
        self._symbol_tables = {}

    @property
    def symbol_tables(self) -> Mapping[Operation, SymbolTable]:
        return self._symbol_tables

    @overload
    def lookup_symbol_in(
        self,
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: Literal[True],
    ) -> list[Operation] | None: ...

    @overload
    def lookup_symbol_in(
        self,
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: Literal[False] = False,
    ) -> Operation | None: ...

    def lookup_symbol_in(
        self,
        op: Operation,
        symbol: StringAttr | SymbolRefAttr | str,
        *,
        all_symbols: bool = False,
    ) -> list[Operation] | Operation | None:
        """
        Look up a symbol with the specified name within the specified symbol table
        operation, returning `None` if no such name exists.
        Accepts either a `StringAttr` or a `SymbolRefAttr`.
        `op` is required to be an operation with the 'xdsl.traits.SymbolTable' trait.
        If `all_symbols` is `True`, returns all symbols referenced by the symbol.
        """
        if isinstance(symbol, str | StringAttr):
            symbol_op = self.get_symbol_table(op).lookup(symbol)
            if all_symbols:
                return [symbol_op] if symbol_op is not None else None
            return symbol_op

        symbols = _lookup_symbol_ref_in(
            op,
            symbol,
            lambda symbol_table_op, name: self.get_symbol_table(symbol_table_op).lookup(
                name
            ),
        )
        if symbols is None:
            return None
        return symbols if all_symbols else symbols[-1]

    @staticmethod
    def lookup_nearest_symbol_from(
        from_op: Operation, symbol: StringAttr | SymbolRefAttr
    ) -> Operation | None:
        """
        Returns the operation registered with the given symbol name within the closest
        parent operation of, or including, `from_op` with the
        [`SymbolTable`][xdsl.traits.SymbolTable] trait.
        Returns `None` if no valid symbol was found.
        """
        raise NotImplementedError

    def get_symbol_table(self, op: Operation) -> SymbolTable:
        """
        Lookup, or create, a symbol table for an operation.
        """
        symbol_table = self._symbol_tables.get(op)
        if symbol_table is None:
            symbol_table = SymbolTable(op)
            self._symbol_tables[op] = symbol_table
        return symbol_table

symbol_tables: Mapping[Operation, SymbolTable] property

__init__() -> None

Source code in xdsl/utils/symbol_table.py
353
354
def __init__(self) -> None:
    self._symbol_tables = {}

lookup_symbol_in(op: Operation, symbol: StringAttr | SymbolRefAttr | str, *, all_symbols: bool = False) -> list[Operation] | Operation | None

lookup_symbol_in(
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: Literal[True],
) -> list[Operation] | None
lookup_symbol_in(
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: Literal[False] = False,
) -> Operation | None

Look up a symbol with the specified name within the specified symbol table operation, returning None if no such name exists. Accepts either a StringAttr or a SymbolRefAttr. op is required to be an operation with the 'xdsl.traits.SymbolTable' trait. If all_symbols is True, returns all symbols referenced by the symbol.

Source code in xdsl/utils/symbol_table.py
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
def lookup_symbol_in(
    self,
    op: Operation,
    symbol: StringAttr | SymbolRefAttr | str,
    *,
    all_symbols: bool = False,
) -> list[Operation] | Operation | None:
    """
    Look up a symbol with the specified name within the specified symbol table
    operation, returning `None` if no such name exists.
    Accepts either a `StringAttr` or a `SymbolRefAttr`.
    `op` is required to be an operation with the 'xdsl.traits.SymbolTable' trait.
    If `all_symbols` is `True`, returns all symbols referenced by the symbol.
    """
    if isinstance(symbol, str | StringAttr):
        symbol_op = self.get_symbol_table(op).lookup(symbol)
        if all_symbols:
            return [symbol_op] if symbol_op is not None else None
        return symbol_op

    symbols = _lookup_symbol_ref_in(
        op,
        symbol,
        lambda symbol_table_op, name: self.get_symbol_table(symbol_table_op).lookup(
            name
        ),
    )
    if symbols is None:
        return None
    return symbols if all_symbols else symbols[-1]

lookup_nearest_symbol_from(from_op: Operation, symbol: StringAttr | SymbolRefAttr) -> Operation | None staticmethod

Returns the operation registered with the given symbol name within the closest parent operation of, or including, from_op with the SymbolTable trait. Returns None if no valid symbol was found.

Source code in xdsl/utils/symbol_table.py
409
410
411
412
413
414
415
416
417
418
419
@staticmethod
def lookup_nearest_symbol_from(
    from_op: Operation, symbol: StringAttr | SymbolRefAttr
) -> Operation | None:
    """
    Returns the operation registered with the given symbol name within the closest
    parent operation of, or including, `from_op` with the
    [`SymbolTable`][xdsl.traits.SymbolTable] trait.
    Returns `None` if no valid symbol was found.
    """
    raise NotImplementedError

get_symbol_table(op: Operation) -> SymbolTable

Lookup, or create, a symbol table for an operation.

Source code in xdsl/utils/symbol_table.py
421
422
423
424
425
426
427
428
429
def get_symbol_table(self, op: Operation) -> SymbolTable:
    """
    Lookup, or create, a symbol table for an operation.
    """
    symbol_table = self._symbol_tables.get(op)
    if symbol_table is None:
        symbol_table = SymbolTable(op)
        self._symbol_tables[op] = symbol_table
    return symbol_table

get_name_if_symbol(op: Operation) -> None | str

Returns the symbol name if this operation has one

Source code in xdsl/utils/symbol_table.py
50
51
52
53
54
55
def get_name_if_symbol(op: Operation) -> None | str:
    """Returns the symbol name if this operation has one"""
    if (sym_interface := op.get_trait(traits.SymbolOpInterface)) is not None and (
        name_attr := sym_interface.get_sym_attr_name(op)
    ) is not None:
        return name_attr.data

walk_symbol_table(op: Operation) -> Iterator[Operation]

Walk all of the operations nested under, and including, the given operation, without traversing into any nested symbol tables.

Source code in xdsl/utils/symbol_table.py
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
def walk_symbol_table(op: Operation) -> Iterator[Operation]:
    """
    Walk all of the operations nested under, and including, the given operation, without
    traversing into any nested symbol tables.
    """
    yield op
    if op.has_trait(traits.SymbolTable):
        return

    regions = list(op.regions)

    while regions:
        region = regions.pop()
        for block in region.blocks:
            for op in block.ops:
                yield op

                if not op.has_trait(traits.SymbolTable):
                    regions.extend(op.regions)