diff --git a/debuginfo-tests/CMakeLists.txt b/debuginfo-tests/CMakeLists.txt --- a/debuginfo-tests/CMakeLists.txt +++ b/debuginfo-tests/CMakeLists.txt @@ -22,6 +22,15 @@ not ) +if ("mlir" IN_LIST LLVM_ENABLE_PROJECTS) + add_llvm_executable(check-gdb-mlir-support + llvm-prettyprinters/gdb/mlir-support.cpp + ) + target_include_directories(check-gdb-mlir-support PRIVATE ${LLVM_EXTERNAL_MLIR_SOURCE_DIR}/include) + target_link_libraries(check-gdb-mlir-support PRIVATE MLIRIR) + list(APPEND DEBUGINFO_TEST_DEPS check-gdb-mlir-support) +endif() + if("compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS) # llgdb-tests/asan.c and other asan* files. if(TARGET asan) diff --git a/debuginfo-tests/lit.cfg.py b/debuginfo-tests/lit.cfg.py --- a/debuginfo-tests/lit.cfg.py +++ b/debuginfo-tests/lit.cfg.py @@ -46,6 +46,7 @@ config.debuginfo_tests_src_root, 'llgdb-tests', 'test_debuginfo.pl')), ToolSubst("%llvm_src_root", config.llvm_src_root), ToolSubst("%llvm_tools_dir", config.llvm_tools_dir), + ToolSubst("%mlir_src_root", config.mlir_src_root), ] def get_required_attr(config, attr_name): diff --git a/debuginfo-tests/lit.site.cfg.py.in b/debuginfo-tests/lit.site.cfg.py.in --- a/debuginfo-tests/lit.site.cfg.py.in +++ b/debuginfo-tests/lit.site.cfg.py.in @@ -20,6 +20,8 @@ config.host_arch = "@HOST_ARCH@" config.is_msvc = lit.util.pythonize_bool("@MSVC@") +config.mlir_src_root = "@MLIR_SOURCE_DIR@" + config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.python3_executable = "@Python3_EXECUTABLE@" diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp new file mode 100644 --- /dev/null +++ b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp @@ -0,0 +1,41 @@ +#include "mlir/IR/Identifier.h" +#include "mlir/IR/Location.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/IR/OperationSupport.h" +#include "mlir/IR/StandardTypes.h" + +mlir::MLIRContext Context; + +auto Identifier = mlir::Identifier::get("foo", &Context); +mlir::OperationName OperationName("FooOp", &Context); +mlir::Value Value({reinterpret_cast(0x8), + mlir::Value::Kind::TrailingOpResult}); + +mlir::Type Type; +mlir::Type IndexType = mlir::IndexType::get(&Context); +mlir::Type IntegerType = + mlir::IntegerType::get(3, mlir::IntegerType::Unsigned, &Context); +mlir::Type FloatType = mlir::Float32Type::get(&Context); +mlir::Type MemRefType = mlir::MemRefType::get({4, 5}, FloatType); +mlir::Type UnrankedMemRefType = mlir::UnrankedMemRefType::get(IntegerType, 6); +mlir::Type VectorType = mlir::VectorType::get({1, 2}, FloatType); +mlir::Type TupleType = + mlir::TupleType::get(mlir::TypeRange({IndexType, FloatType}), &Context); + +auto UnknownLoc = mlir::UnknownLoc::get(&Context); +auto FileLineColLoc = mlir::FileLineColLoc::get("file", 7, 8, &Context); +auto OpaqueLoc = mlir::OpaqueLoc::get(9, &Context); +auto NameLoc = mlir::NameLoc::get(Identifier, &Context); +auto CallSiteLoc = mlir::CallSiteLoc::get(FileLineColLoc, OpaqueLoc); +auto FusedLoc = mlir::FusedLoc::get({FileLineColLoc, NameLoc}, &Context); + +mlir::Attribute UnitAttr = mlir::UnitAttr::get(&Context); +mlir::Attribute FloatAttr = mlir::FloatAttr::get(FloatType, 1.0); +mlir::Attribute IntegerAttr = mlir::IntegerAttr::get(IntegerType, 10); +mlir::Attribute TypeAttr = mlir::TypeAttr::get(IndexType); +mlir::Attribute ArrayAttr = mlir::ArrayAttr::get({}, &Context); +mlir::Attribute StringAttr = mlir::StringAttr::get("foo", &Context); +mlir::Attribute ElementsAttr = mlir::DenseElementsAttr::get( + VectorType.cast(), llvm::ArrayRef{2.0f, 3.0f}); + +int main() { return 0; } diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb new file mode 100644 --- /dev/null +++ b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb @@ -0,0 +1,110 @@ +# RUN: gdb -q -batch -n -iex 'source %mlir_src_root/utils/gdb-scripts/prettyprinters.py' -x %s %llvm_tools_dir/check-gdb-mlir-support | FileCheck %s --dump-input=fail +# REQUIRES: debug-info + +break main +run + +# CHECK: "foo" +p Identifier + +# CHECK: "FooOp" +p OperationName + +# CHECK: 0x8 +# CHECK: TrailingOpResult +p Value + +# CHECK: impl = 0x0 +p Type + +# CHECK: cast +p IndexType + +# CHECK: cast +# CHECK: width = 3 +# CHECK: Unsigned +p IntegerType + +# CHECK: cast +p FloatType + +# CHECK: cast +# CHECK: shapeSize = 2 +# CHECK: shapeElements[0] = 4 +# CHECK: shapeElements[1] = 5 +p MemRefType + +# CHECK: cast +# CHECK: memorySpace = 6 +p UnrankedMemRefType + +# CHECK: cast +# CHECK: shapeSize = 2 +# CHECK: shapeElements[0] = 1 +# CHECK: shapeElements[1] = 2 +p VectorType + +# CHECK: cast +# CHECK: numElements = 2 +# CHECK: elements[0] +# CHECK: mlir::IndexType +# CHECK: elements[1] +# CHECK: mlir::Float32Type +p TupleType + +# CHECK: cast +p UnknownLoc + +# CHECK: cast +# CHECK: filename = "file", +# CHECK: line = 1, +# CHECK: column = 2 +p FileLineColLoc + +# CHECK: cast +# CHECK: underlyingLocation = 9 +p OpaqueLoc + +# CHECK: cast +# CHECK: name = "foo" +# CHECK: mlir::UnknownLoc +p NameLoc + +# CHECK: cast +# CHECK: callee +# CHECK: mlir::FileLineColLoc +# CHECK: caller +# CHECK: mlir::OpaqueLoc +p CallSiteLoc + +# CHECK: cast +# CHECK: numLocs = 2 +# CHECK: locs[0] +# CHECK: mlir::FileLineColLoc +# CHECK: locs[1] +# CHECK: mlir::NameLoc +p FusedLoc + +# CHECK: cast +p UnitAttr + +# CHECK: cast +p FloatAttr + +# CHECK: cast +p IntegerAttr + +# CHECK: cast +# CHECK: mlir::IndexType +p TypeAttr + +# CHECK: cast +# CHECK: llvm::ArrayRef of length 0 +p ArrayAttr + +# CHECK: cast +# CHECK: value = "foo" +p StringAttribute + +# CHECK: cast +p ElementsAttr diff --git a/mlir/utils/gdb-scripts/prettyprinters.py b/mlir/utils/gdb-scripts/prettyprinters.py new file mode 100644 --- /dev/null +++ b/mlir/utils/gdb-scripts/prettyprinters.py @@ -0,0 +1,235 @@ +"""GDB pretty printers for MLIR types.""" + +import gdb.printing + + +class IdentifierPrinter: + """Prints an mlir::Identifier instance.""" + + def __init__(self, val): + self.entry = val['entry'] + + def to_string(self): + ptr = (self.entry + 1).cast(gdb.lookup_type('char').pointer()) + return ptr.string(length=self.entry['keyLength']) + + def display_hint(self): + return 'string' + + +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]) + + +class TupleTypeStoragePrinter(StoragePrinter): + + def children(self): + for child in StoragePrinter.children(self): + yield child + elements = (self.val.address + 1).cast(gdb.lookup_type('mlir::Type*')) + for i in range(self.val['numElements']): + yield 'elements[%u]' % i, elements[i] + + +class RankedTypeStoragePrinter(StoragePrinter): + + def children(self): + for child in StoragePrinter.children(self): + yield child + for i in range(self.val['shapeSize']): + yield 'shapeElements[%u]' % i, self.val['shapeElements'][i] + + +class MemRefTypeStoragePrinter(RankedTypeStoragePrinter): + + def children(self): + for child in RankedTypeStoragePrinter.children(self): + yield child + for i in range(self.val['numAffineMaps']): + yield 'affineMapsList[%u]' % i, self.val['affineMapsList'][i] + + +class FusedLocationStoragePrinter(StoragePrinter): + + def children(self): + for child in StoragePrinter.children(self): + yield child + elements = (self.val.address + 1).cast(gdb.lookup_type('mlir::Location*')) + for i in range(self.val['numLocs']): + yield 'locs[%u]' % i, elements[i] + + +class StorageUserBasePrinter: + """Printer for an mlir::detail::StorageUserBase instance.""" + + def __init__(self, val): + self.val = val + + def children(self): + storage_type = self.val.type.template_argument(2) + yield 'impl', self.val['impl'].dereference().cast(storage_type) + + +class StorageTypeMap: + """Maps a TypeID to the corresponding type derived from StorageUserBase. + + Types need to be registered by name before the first lookup. + """ + + def _get_key(self, type_id): + return int(type_id['storage']) + + 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: + type_id = gdb.parse_and_eval('%s::getTypeID()' % type_name) + concrete_type = gdb.lookup_type(type_name) + if type_id and concrete_type: + self.map[self._get_key(type_id)] = concrete_type + + def __getitem__(self, type_id): + self._init_map() + return self.map.get(self._get_key(type_id)) + + +storage_type_map = StorageTypeMap() + + +def get_type_id_printer(val): + """Returns a printer of the name of a mlir::TypeID.""" + + class StringPrinter: + + 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 StringPrinter('"%s"' % concrete_type.name) + + +def get_attr_or_type_printer(val, get_type_id): + """Returns a printer for mlir::Attribute or mlir::Type.""" + + class UpcastPrinter: + + def __init__(self, val, type): + self.val = val.cast(type) + + def children(self): + yield 'cast<%s>' % self.val.type.name, self.val + + if not val['impl']: + return None + type_id = get_type_id(val['impl'].dereference()) + concrete_type = storage_type_map[type_id] + if not concrete_type: + return None + return UpcastPrinter(val, concrete_type) + + +pp = gdb.printing.RegexpCollectionPrettyPrinter('MLIRSupport') + +pp.add_printer('mlir::Identifier', '^mlir::Identifier$', IdentifierPrinter) + +# Printers for types deriving from AttributeStorage or TypeStorage. +pp.add_printer('mlir::detail::FusedLocationStorage', + '^mlir::detail::FusedLocationStorage', + FusedLocationStoragePrinter) +pp.add_printer('mlir::detail::VectorTypeStorage', + '^mlir::detail::VectorTypeStorage', RankedTypeStoragePrinter) +pp.add_printer('mlir::detail::RankedTensorTypeStorage', + '^mlir::detail::RankedTensorTypeStorage', + RankedTypeStoragePrinter) +pp.add_printer('mlir::detail::MemRefTypeStorage', + '^mlir::detail::MemRefTypeStorage$', MemRefTypeStoragePrinter) +pp.add_printer('mlir::detail::TupleTypeStorage', + '^mlir::detail::TupleTypeStorage$', TupleTypeStoragePrinter) + +# Printers for Attribute::AttrBase or Type::TypeBase typedefs. +pp.add_printer('mlir::detail::StorageUserBase', + '^mlir::detail::StorageUserBase<.*>$', StorageUserBasePrinter) + +# 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', + 'OpaqueElementsAttr', + 'SparseElementsAttr', + # mlir/IR/StandardTypes.h + 'ComplexType', + 'IndexType', + 'IntegerType', + 'Float16Type', + 'Float32Type', + 'Float64Type', + '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. + +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)) + pp.add_printer('mlir::%sStorage' % name, '^mlir::%sStorage$' % name, + lambda val: get_type_id_printer(get_type_id(val))) + + +# 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)