xref: /llvm-project/mlir/utils/gdb-scripts/prettyprinters.py (revision 6685fd82391d3e654d3b05f2d54cdcdec6e6d887)
1"""GDB pretty printers for MLIR types."""
2
3import gdb.printing
4
5
6class StoragePrinter:
7    """Prints bases of a struct and its fields."""
8
9    def __init__(self, val):
10        self.val = val
11
12    def children(self):
13        for field in self.val.type.fields():
14            if field.is_base_class:
15                yield "<%s>" % field.name, self.val.cast(field.type)
16            else:
17                yield field.name, self.val[field.name]
18
19    def to_string(self):
20        return "mlir::Storage"
21
22
23class TupleTypeStoragePrinter(StoragePrinter):
24    def children(self):
25        for child in StoragePrinter.children(self):
26            yield child
27        pointer_type = gdb.lookup_type("mlir::Type").pointer()
28        elements = (self.val.address + 1).cast(pointer_type)
29        for i in range(self.val["numElements"]):
30            yield "elements[%u]" % i, elements[i]
31
32    def to_string(self):
33        return "mlir::TupleTypeStorage of %u elements" % self.val["numElements"]
34
35
36class FusedLocationStoragePrinter(StoragePrinter):
37    def children(self):
38        for child in StoragePrinter.children(self):
39            yield child
40        pointer_type = gdb.lookup_type("mlir::Location").pointer()
41        elements = (self.val.address + 1).cast(pointer_type)
42        for i in range(self.val["numLocs"]):
43            yield "locs[%u]" % i, elements[i]
44
45    def to_string(self):
46        return "mlir::FusedLocationStorage of %u locs" % self.val["numLocs"]
47
48
49class StorageTypeMap:
50    """Maps a TypeID to the corresponding concrete type.
51
52    Types need to be registered by name before the first lookup.
53    """
54
55    def __init__(self):
56        self.map = None
57        self.type_names = []
58
59    def register_type(self, type_name):
60        assert not self.map, "register_type called after __getitem__"
61        self.type_names += [type_name]
62
63    def _init_map(self):
64        """Lazy initialization  of self.map."""
65        if self.map:
66            return
67        self.map = {}
68        for type_name in self.type_names:
69            concrete_type = gdb.lookup_type(type_name)
70            try:
71                storage = gdb.parse_and_eval(
72                    "&'mlir::detail::TypeIDExported::get<%s>()::instance'" % type_name
73                )
74            except gdb.error:
75                # Skip when TypeID instance cannot be found in current context.
76                continue
77            if concrete_type and storage:
78                self.map[int(storage)] = concrete_type
79
80    def __getitem__(self, type_id):
81        self._init_map()
82        return self.map.get(int(type_id["storage"]))
83
84
85storage_type_map = StorageTypeMap()
86
87
88def get_type_id_printer(val):
89    """Returns a printer of the name of a mlir::TypeID."""
90
91    class TypeIdPrinter:
92        def __init__(self, string):
93            self.string = string
94
95        def to_string(self):
96            return self.string
97
98    concrete_type = storage_type_map[val]
99    if not concrete_type:
100        return None
101    return TypeIdPrinter("mlir::TypeID::get<%s>()" % concrete_type)
102
103
104def get_attr_or_type_printer(val, get_type_id):
105    """Returns a printer for mlir::Attribute or mlir::Type."""
106
107    class AttrOrTypePrinter:
108        def __init__(self, type_id, impl):
109            self.type_id = type_id
110            self.impl = impl
111
112        def children(self):
113            yield "typeID", self.type_id
114            yield "impl", self.impl
115
116        def to_string(self):
117            return "cast<%s>" % self.impl.type
118
119    if not val["impl"]:
120        return None
121    impl = val["impl"].dereference()
122    type_id = get_type_id(impl)
123    concrete_type = storage_type_map[type_id]
124    if not concrete_type:
125        return None
126    # 3rd template argument of StorageUserBase is the storage type.
127    storage_type = concrete_type.fields()[0].type.template_argument(2)
128    if not storage_type:
129        return None
130    return AttrOrTypePrinter(type_id, impl.cast(storage_type))
131
132
133class ImplPrinter:
134    """Printer for an instance with a single 'impl' member pointer."""
135
136    def __init__(self, val):
137        self.val = val
138        self.impl = val["impl"]
139
140    def children(self):
141        if self.impl:
142            yield "impl", self.impl.dereference()
143
144    def to_string(self):
145        return self.val.type.name
146
147
148# Printers of types deriving from Attribute::AttrBase or Type::TypeBase.
149for name in [
150    # mlir/IR/Attributes.h
151    "ArrayAttr",
152    "DictionaryAttr",
153    "FloatAttr",
154    "IntegerAttr",
155    "IntegerSetAttr",
156    "OpaqueAttr",
157    "StringAttr",
158    "SymbolRefAttr",
159    "TypeAttr",
160    "UnitAttr",
161    "DenseStringElementsAttr",
162    "DenseIntOrFPElementsAttr",
163    "SparseElementsAttr",
164    # mlir/IR/BuiltinTypes.h
165    "ComplexType",
166    "IndexType",
167    "IntegerType",
168    "Float16Type",
169    "FloatTF32Type",
170    "Float32Type",
171    "Float64Type",
172    "Float80Type",
173    "Float128Type",
174    "NoneType",
175    "VectorType",
176    "RankedTensorType",
177    "UnrankedTensorType",
178    "MemRefType",
179    "UnrankedMemRefType",
180    "TupleType",
181    # mlir/IR/Location.h
182    "CallSiteLoc",
183    "FileLineColLoc",
184    "FusedLoc",
185    "NameLoc",
186    "OpaqueLoc",
187    "UnknownLoc",
188]:
189    storage_type_map.register_type("mlir::%s" % name)  # Register for upcasting.
190storage_type_map.register_type("void")  # Register default.
191
192
193pp = gdb.printing.RegexpCollectionPrettyPrinter("MLIRSupport")
194
195pp.add_printer("mlir::OperationName", "^mlir::OperationName$", ImplPrinter)
196pp.add_printer("mlir::Value", "^mlir::Value$", ImplPrinter)
197
198# Printers for types deriving from AttributeStorage or TypeStorage.
199pp.add_printer(
200    "mlir::detail::FusedLocationStorage",
201    "^mlir::detail::FusedLocationStorage",
202    FusedLocationStoragePrinter,
203)
204pp.add_printer(
205    "mlir::detail::TupleTypeStorage",
206    "^mlir::detail::TupleTypeStorage$",
207    TupleTypeStoragePrinter,
208)
209
210pp.add_printer("mlir::TypeID", "^mlir::TypeID$", get_type_id_printer)
211
212
213def add_attr_or_type_printers(name):
214    """Adds printers for mlir::Attribute or mlir::Type and their Storage type."""
215    get_type_id = lambda val: val["abstract%s" % name]["typeID"]
216    pp.add_printer(
217        "mlir::%s" % name,
218        "^mlir::%s$" % name,
219        lambda val: get_attr_or_type_printer(val, get_type_id),
220    )
221
222
223# Upcasting printers of mlir::Attribute and mlir::Type.
224for name in ["Attribute", "Type"]:
225    add_attr_or_type_printers(name)
226
227gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
228