diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h @@ -51,6 +51,51 @@ static bool classof(Attribute attr); }; +namespace detail { +class DICompositeTypeMutAttrStorage; +} // namespace detail + +/// A mutable debug information attribute that describes a composite type. +class DICompositeTypeMutAttr + : public Attribute::AttrBase { +public: + /// Inherit base constructors. + using Base::Base; + + /// Returns the composite type with the given identifier and name. + static DICompositeTypeMutAttr get(MLIRContext *context, int64_t id, + StringAttr name, DITypeAttr bastType); + + // static DICompositeTypeMutAttr getDistinct(int64_t id, StringAttr name); + + /// Returns the keyword used when printing and parsing the composite type. + static constexpr StringLiteral getMnemonic() { + return {"di_composite_type_mut"}; + } + + LogicalResult setElements(ArrayRef elements); + + /// Returns the unique id of the composite type. + int64_t getID() const; + + /// Returns the name of the composite type. + StringAttr getName() const; + + /// Returns the base type of the composite type. + DITypeAttr getBaseType() const; + + /// Returns the element types of the composite type. + ArrayRef getElements() const; + + /// Parses an instance of this attribute. + static Attribute parse(AsmParser &parser, Type type); + + /// Prints this attribute. + void print(AsmPrinter &os) const; +}; + // Inline the LLVM generated Linkage enum and utility. // This is only necessary to isolate the "enum generated code" from the // attribute definition itself. diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td @@ -27,7 +27,7 @@ let name = "llvm"; let cppNamespace = "::mlir::LLVM"; - let useDefaultAttributePrinterParser = 1; + //let useDefaultAttributePrinterParser = 1; let hasRegionArgAttrVerify = 1; let hasRegionResultAttrVerify = 1; let hasOperationAttrVerify = 1; @@ -81,8 +81,11 @@ return "llvm.readnone"; } - Type parseType(DialectAsmParser &p) const override; - void printType(Type, DialectAsmPrinter &p) const override; + Type parseType(DialectAsmParser &parser) const override; + void printType(Type type, DialectAsmPrinter &os) const override; + + Attribute parseAttribute(DialectAsmParser &parser, Type type) const override; + void printAttribute(Attribute attr, DialectAsmPrinter &os) const override; private: /// Register all types. diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -12,11 +12,15 @@ #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/Attributes.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" +#include "mlir/IR/OpDefinition.h" +#include "mlir/Support/LogicalResult.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/TypeSwitch.h" #include "llvm/BinaryFormat/Dwarf.h" +#include #include using namespace mlir; @@ -31,6 +35,7 @@ //===----------------------------------------------------------------------===// void LLVMDialect::registerAttributes() { + addAttributes(); addAttributes< #define GET_ATTRDEF_LIST #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc" @@ -65,7 +70,8 @@ bool DITypeAttr::classof(Attribute attr) { return llvm::isa(attr); + DICompositeTypeMutAttr, DIDerivedTypeAttr, + DISubroutineTypeAttr>(attr); } //===----------------------------------------------------------------------===// @@ -85,6 +91,209 @@ return success(); } +//===----------------------------------------------------------------------===// +// DICompositeTypeMutAttr +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace LLVM { +namespace detail { +// TODO move to LLVMAttersDetail.h? +class DICompositeTypeMutAttrStorage : public AttributeStorage { +public: + using KeyTy = std::tuple; + + DICompositeTypeMutAttrStorage(int64_t id, StringAttr name, + DITypeAttr baseType) + : id(id), name(name), baseType(baseType) {} + + KeyTy getAsKey() const { return KeyTy(id, name, baseType); } + + static llvm::hash_code hashKey(const KeyTy &key) { + return llvm::hash_combine(std::get<0>(key), std::get<1>(key), + std::get<2>(key)); + } + + static DICompositeTypeMutAttrStorage * + construct(AttributeStorageAllocator &allocator, const KeyTy &key) { + int64_t id = std::get<0>(key); + StringAttr name = std::get<1>(key); + DITypeAttr baseType = std::get<2>(key); + return new (allocator.allocate()) + DICompositeTypeMutAttrStorage(id, name, baseType); + } + + LogicalResult mutate(AttributeStorageAllocator &allocator, + ArrayRef elements) { + if (isMutated) + return failure(); + + ArrayRef allocated = allocator.copyInto(elements); + elementsPtr = allocated.data(); + elementsSize = allocated.size(); + isMutated = true; + return success(); + } + + bool operator==(const KeyTy &other) const { return getAsKey() == other; } + + /// Returns the list of types contained in an identified struct. + ArrayRef getElements() const { + return ArrayRef(elementsPtr, elementsSize); + } + + // TODO make stuff blow private + int64_t id; + StringAttr name; + DITypeAttr baseType; + + bool isMutated = false; + const DITypeAttr *elementsPtr = nullptr; + size_t elementsSize = 0; +}; +} // namespace detail +} // namespace LLVM +} // namespace mlir + +DICompositeTypeMutAttr DICompositeTypeMutAttr::get(MLIRContext *context, + int64_t id, StringAttr name, + DITypeAttr baseType) { + return Base::get(context, id, name, baseType); +} + +int64_t DICompositeTypeMutAttr::getID() const { return getImpl()->id; } + +StringAttr DICompositeTypeMutAttr::getName() const { return getImpl()->name; } + +DITypeAttr DICompositeTypeMutAttr::getBaseType() const { + return getImpl()->baseType; +} + +LogicalResult +DICompositeTypeMutAttr::setElements(ArrayRef elements) { + return Base::mutate(elements); +} + +ArrayRef DICompositeTypeMutAttr::getElements() const { + return getImpl()->getElements(); +} + +Attribute DICompositeTypeMutAttr::parse(AsmParser &parser, Type type) { + if (parser.parseLess()) + return {}; + + // A helper function to parse a composite type parameter. + auto parseParameter = + [&](StringRef name, StringRef type, bool &seen, + function_ref parseFn) -> ParseResult { + if (seen) { + return parser.emitError(parser.getCurrentLocation()) + << "struct has duplicate parameter '" << name << "'"; + } + if (failed(parseFn())) { + return parser.emitError(parser.getCurrentLocation()) + << "failed to parse LLVM_DICompositeTypeAttr parameter '" << name + << "' which is to be a '" << type << "'"; + } + seen = true; + return success(); + }; + + std::pair id = {0, false}; + std::pair name = {nullptr, false}; + std::pair baseType = {nullptr, false}; + std::pair, bool> elements = {{}, false}; + do { + std::string keyword; + if (failed(parser.parseKeywordOrString(&keyword))) { + parser.emitError(parser.getCurrentLocation()) + << "expected a parameter name in struct"; + return {}; + } + if (parser.parseEqual()) + return {}; + + if (keyword == "id") { + if (failed(parseParameter(keyword, "int64_t", id.second, [&]() { + return parser.parseInteger(id.first); + }))) + return {}; + } else if (keyword == "name") { + if (failed(parseParameter(keyword, "StringAttr", name.second, [&]() { + return parser.parseAttribute(name.first); + }))) + return {}; + } else if (keyword == "base_type") { + if (failed(parseParameter(keyword, "DITypeAttr", baseType.second, [&]() { + return parser.parseAttribute(baseType.first); + }))) + return {}; + } else if (keyword == "elements") { + if (failed(parseParameter( + keyword, "::llvm::ArrayRef", elements.second, [&]() { + return parser.parseCommaSeparatedList([&]() { + return parser.parseAttribute(elements.first.emplace_back()); + }); + }))) + return {}; + } else { + parser.emitError(parser.getCurrentLocation()) + << "expected a parameter name in struct"; + return {}; + } + } while (succeeded(parser.parseOptionalComma())); + + if (!id.second) { + parser.emitError(parser.getCurrentLocation()) + << "struct is missing required parameter 'id'"; + return {}; + } + if (!name.second) { + parser.emitError(parser.getCurrentLocation()) + << "struct is missing required parameter 'name'"; + return {}; + } + + if (parser.parseGreater()) + return {}; + + DICompositeTypeMutAttr attr = + get(parser.getContext(), id.first, name.first, baseType.first); + if (elements.second) + if (failed(attr.setElements(elements.first))) { + parser.emitError(parser.getCurrentLocation()) + << "cannot mutate 'elements' twice"; + return {}; + } + return attr; +} + +void DICompositeTypeMutAttr::print(AsmPrinter &os) const { + + thread_local SetVector knownAttributes; + // TODO add stack size assertion? + + os << DICompositeTypeMutAttr::getMnemonic() << "<"; + os << "id = " << getID(); + os << ", name = "; + os.printStrippedAttrOrType(getName()); + if (getBaseType()) { + os << ", base_type = "; + os.printStrippedAttrOrType(getBaseType()); + } + if (getImpl()->isMutated && knownAttributes.count(getTypeID()) == 0) { + knownAttributes.insert(getTypeID()); + + os << ", elements = "; + llvm::interleaveComma(getElements(), os, [&](auto typeAttr) { + os.printStrippedAttrOrType(typeAttr); + }); + + knownAttributes.pop_back(); + } + os << ">"; +} + //===----------------------------------------------------------------------===// // LoopOptionsAttrBuilder //===----------------------------------------------------------------------===// @@ -254,3 +463,32 @@ llvm::sort(options, llvm::less_first()); return get(parser.getContext(), options); } + +//===----------------------------------------------------------------------===// +// LLVMDialect +//===----------------------------------------------------------------------===// + +Attribute LLVMDialect::parseAttribute(DialectAsmParser &parser, + Type type) const { + StringRef mnemonic; + Attribute attr; + OptionalParseResult result = + generatedAttributeParser(parser, &mnemonic, type, attr); + if (result.has_value()) + return attr; + + if (mnemonic == DICompositeTypeMutAttr::getMnemonic()) + return DICompositeTypeMutAttr::parse(parser, type); + + llvm_unreachable("unhandled LLVM attribute kind"); +} + +void LLVMDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const { + if (succeeded(generatedAttributePrinter(attr, os))) + return; + + if (auto composite = dyn_cast(attr)) + composite.print(os); + else + llvm_unreachable("unhandled LLVM attribute kind"); +} diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "TypeDetail.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" @@ -2833,12 +2834,13 @@ AliasResult getAlias(Attribute attr, raw_ostream &os) const override { return TypeSwitch(attr) .Case([&](auto attr) { - os << decltype(attr)::getMnemonic(); - return AliasResult::OverridableAlias; - }) + DICompositeTypeAttr, DICompositeTypeMutAttr, DIDerivedTypeAttr, + DIFileAttr, DILexicalBlockAttr, DILexicalBlockFileAttr, + DILocalVariableAttr, DISubprogramAttr, DISubroutineTypeAttr>( + [&](auto attr) { + os << decltype(attr)::getMnemonic(); + return AliasResult::OverridableAlias; + }) .Default([](Attribute) { return AliasResult::NoAlias; }); } }; diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp --- a/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp +++ b/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp @@ -13,6 +13,7 @@ #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/Linalg/IR/Linalg.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" diff --git a/mlir/test/Dialect/LLVMIR/debuginfo_test.mlir b/mlir/test/Dialect/LLVMIR/debuginfo_test.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/debuginfo_test.mlir @@ -0,0 +1,41 @@ +// RUN: mlir-opt %s | mlir-opt | FileCheck %s + +#file = #llvm.di_file<"debuginfo.mlir" in "/test/"> +#cu = #llvm.di_compile_unit< + sourceLanguage = DW_LANG_C, file = #file, producer = "MLIR", + isOptimized = true, emissionKind = Full +> +#void = #llvm.di_void_result_type +#int0 = #llvm.di_basic_type< + tag = DW_TAG_base_type, name = "int0" +> +#derived = #llvm.di_derived_type + + +#comp0 = #llvm.di_composite_type_mut> + +#comp1 = #llvm.di_composite_type_mut + +//#comp2 = #llvm.di_composite_type_mut + +// #ptr = #llvm.di_derived_type + +// #comp0 = #llvm.di_composite_type< +// tag = DW_TAG_array_type, name = "array0", +// line = 10, sizeInBits = 128, alignInBits = 32, +// elements = #int0 +// > + +#spType0 = #llvm.di_subroutine_type< + callingConvention = DW_CC_normal, types = #void, #comp0, #comp1 //, #comp2 +> + +#sp0 = #llvm.di_subprogram< + // Omit the optional linkageName parameter. + compileUnit = #cu, scope = #file, name = "value", + file = #file, subprogramFlags = "Definition", type = #spType0 +> + +llvm.func @value() { + llvm.return +} loc(fused<#sp0>["foo.mlir":1:1])