"""GDB pretty printers for MLIR types.""" import gdb.printing class StoragePrinter: """Prints bases of a struct and its fields.""" def __init__(self, val): self.val = val def children(self): for field in self.val.type.fields(): if field.is_base_class: yield '<%s>' % field.name, self.val.cast(field.type) else: yield field.name, self.val[field.name] def to_string(self): return 'mlir::Storage' class TupleTypeStoragePrinter(StoragePrinter): def children(self): for child in StoragePrinter.children(self): yield child pointer_type = gdb.lookup_type('mlir::Type').pointer() elements = (self.val.address + 1).cast(pointer_type) for i in range(self.val['numElements']): yield 'elements[%u]' % i, elements[i] def to_string(self): return 'mlir::TupleTypeStorage of %u elements' % self.val['numElements'] class FusedLocationStoragePrinter(StoragePrinter): def children(self): for child in StoragePrinter.children(self): yield child pointer_type = gdb.lookup_type('mlir::Location').pointer() elements = (self.val.address + 1).cast(pointer_type) for i in range(self.val['numLocs']): yield 'locs[%u]' % i, elements[i] def to_string(self): return 'mlir::FusedLocationStorage of %u locs' % self.val['numLocs'] class StorageTypeMap: """Maps a TypeID to the corresponding concrete type. Types need to be registered by name before the first lookup. """ def __init__(self): self.map = None self.type_names = [] def register_type(self, type_name): assert not self.map, 'register_type called after __getitem__' self.type_names += [type_name] def _init_map(self): """Lazy initialization of self.map.""" if self.map: return self.map = {} for type_name in self.type_names: concrete_type = gdb.lookup_type(type_name) try: storage = gdb.parse_and_eval( "&'mlir::detail::TypeIDExported::get<%s>()::instance'" % type_name) except gdb.error: # Skip when TypeID instance cannot be found in current context. continue if concrete_type and storage: self.map[int(storage)] = concrete_type def __getitem__(self, type_id): self._init_map() return self.map.get(int(type_id['storage'])) storage_type_map = StorageTypeMap() def get_type_id_printer(val): """Returns a printer of the name of a mlir::TypeID.""" class TypeIdPrinter: def __init__(self, string): self.string = string def to_string(self): return self.string concrete_type = storage_type_map[val] if not concrete_type: return None return TypeIdPrinter('mlir::TypeID::get<%s>()' % concrete_type) def get_attr_or_type_printer(val, get_type_id): """Returns a printer for mlir::Attribute or mlir::Type.""" class AttrOrTypePrinter: def __init__(self, type_id, impl): self.type_id = type_id self.impl = impl def children(self): yield 'typeID', self.type_id yield 'impl', self.impl def to_string(self): return 'cast<%s>' % self.impl.type if not val['impl']: return None impl = val['impl'].dereference() type_id = get_type_id(impl) concrete_type = storage_type_map[type_id] if not concrete_type: return None # 3rd template argument of StorageUserBase is the storage type. storage_type = concrete_type.fields()[0].type.template_argument(2) if not storage_type: return None return AttrOrTypePrinter(type_id, impl.cast(storage_type)) class ImplPrinter: """Printer for an instance with a single 'impl' member pointer.""" def __init__(self, val): self.val = val self.impl = val['impl'] def children(self): if self.impl: yield 'impl', self.impl.dereference() def to_string(self): return self.val.type.name # Printers of types deriving from Attribute::AttrBase or Type::TypeBase. for name in [ # mlir/IR/Attributes.h 'ArrayAttr', 'DictionaryAttr', 'FloatAttr', 'IntegerAttr', 'IntegerSetAttr', 'OpaqueAttr', 'StringAttr', 'SymbolRefAttr', 'TypeAttr', 'UnitAttr', 'DenseStringElementsAttr', 'DenseIntOrFPElementsAttr', 'SparseElementsAttr', # mlir/IR/BuiltinTypes.h 'ComplexType', 'IndexType', 'IntegerType', 'Float16Type', 'Float32Type', 'Float64Type', 'Float80Type', 'Float128Type', 'NoneType', 'VectorType', 'RankedTensorType', 'UnrankedTensorType', 'MemRefType', 'UnrankedMemRefType', 'TupleType', # mlir/IR/Location.h 'CallSiteLoc', 'FileLineColLoc', 'FusedLoc', 'NameLoc', 'OpaqueLoc', 'UnknownLoc' ]: storage_type_map.register_type('mlir::%s' % name) # Register for upcasting. storage_type_map.register_type('void') # Register default. pp = gdb.printing.RegexpCollectionPrettyPrinter('MLIRSupport') pp.add_printer('mlir::OperationName', '^mlir::OperationName$', ImplPrinter) pp.add_printer('mlir::Value', '^mlir::Value$', ImplPrinter) # Printers for types deriving from AttributeStorage or TypeStorage. pp.add_printer('mlir::detail::FusedLocationStorage', '^mlir::detail::FusedLocationStorage', FusedLocationStoragePrinter) pp.add_printer('mlir::detail::TupleTypeStorage', '^mlir::detail::TupleTypeStorage$', TupleTypeStoragePrinter) pp.add_printer('mlir::TypeID', '^mlir::TypeID$', get_type_id_printer) def add_attr_or_type_printers(name): """Adds printers for mlir::Attribute or mlir::Type and their Storage type.""" get_type_id = lambda val: val['abstract%s' % name]['typeID'] pp.add_printer('mlir::%s' % name, '^mlir::%s$' % name, lambda val: get_attr_or_type_printer(val, get_type_id)) # Upcasting printers of mlir::Attribute and mlir::Type. for name in ['Attribute', 'Type']: add_attr_or_type_printers(name) gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)