[mlir:LLVM] Add attribute/op definitions for debug info
authorRiver Riddle <riddleriver@gmail.com>
Sat, 22 Oct 2022 21:13:20 +0000 (14:13 -0700)
committerRiver Riddle <riddleriver@gmail.com>
Mon, 24 Oct 2022 06:59:55 +0000 (23:59 -0700)
This adds a subset of the necessary metadata for defining
debug info in the LLVM dialect. It doesn't import everything,
but just enough to start actually generating LLVM debug info
the expected way. Export/Import to LLVMIR will be added in a
followup.

Differential Revision: https://reviews.llvm.org/D136542

mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
mlir/lib/Dialect/LLVMIR/CMakeLists.txt
mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/test/Dialect/LLVMIR/debuginfo.mlir [new file with mode: 0644]

index a4df5fa..b6b1f4c 100644 (file)
 include "mlir/IR/AttrTypeBase.td"
 include "mlir/Dialect/LLVMIR/LLVMEnums.td"
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
+include "mlir/IR/SubElementInterfaces.td"
 
 // All of the attributes will extend this class.
-class LLVM_Attr<string name, string attrMnemonic>
-    : AttrDef<LLVM_Dialect, name, /*traits=*/[]> {
+class LLVM_Attr<string name, string attrMnemonic,
+                list<Trait> traits = [],
+                string baseCppClass = "::mlir::Attribute">
+    : AttrDef<LLVM_Dialect, name, traits, baseCppClass> {
   let mnemonic = attrMnemonic;
 }
 
@@ -81,4 +84,280 @@ def LoopOptionsAttr : LLVM_Attr<"LoopOptions", "loopopts"> {
   let skipDefaultBuilders = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// DebugInfo Attributes
+//===----------------------------------------------------------------------===//
+
+class LLVM_DIParameter<string summary, string underlyingType, string parseName,
+                       string printName = parseName>
+    : AttrOrTypeParameter<underlyingType, "debug info " # summary> {
+  let parser = [{ [&]() -> FailureOr<unsigned> {
+    SMLoc tagLoc = $_parser.getCurrentLocation(); 
+    StringRef name;
+    if ($_parser.parseKeyword(&name))
+      return failure();
+
+    if (unsigned tag = llvm::dwarf::get}] # parseName # [{(name))
+      return tag;
+    return $_parser.emitError(tagLoc)
+      << "invalid debug info }] # summary # [{ name: " << name;
+  }() }];
+  let printer = "$_printer << llvm::dwarf::" # printName # "String($_self)";
+}
+
+def LLVM_DICallingConventionParameter : LLVM_DIParameter<
+  "calling convention", "unsigned", "CallingConvention", "Convention" 
+>;
+
+def LLVM_DIEncodingParameter : LLVM_DIParameter<
+  "encoding", "unsigned", "AttributeEncoding"
+>;
+
+def LLVM_DILanguageParameter : LLVM_DIParameter<
+  "language", "unsigned", "Language"
+>;
+
+def LLVM_DITagParameter : LLVM_DIParameter<
+  "tag", "unsigned", "Tag"
+>;
+
+//===----------------------------------------------------------------------===//
+// DIBasicTypeAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIBasicTypeAttr : LLVM_Attr<"DIBasicType", "di_basic_type",
+                                     /*traits=*/[], "DITypeAttr"> {
+  let parameters = (ins
+    LLVM_DITagParameter:$tag,
+    "StringAttr":$name,
+    "uint64_t":$sizeInBits,
+    LLVM_DIEncodingParameter:$encoding
+  );
+
+  let builders = [
+    TypeBuilder<(ins
+      "unsigned":$tag, "const Twine &":$name, "uint64_t":$sizeInBits,
+      "unsigned":$encoding
+    ), [{
+      return $_get($_ctxt, tag, StringAttr::get($_ctxt, name), sizeInBits,
+                   encoding);
+    }]>
+  ];
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DICompileUnitAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DIScopeAttr"> {
+  let parameters = (ins
+    LLVM_DILanguageParameter:$sourceLanguage,
+    "DIFileAttr":$file,
+    "StringAttr":$producer,
+    "bool":$isOptimized,
+    "DIEmissionKind":$emissionKind
+  );
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DICompositeTypeAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DITypeAttr"> {
+  let parameters = (ins
+    LLVM_DITagParameter:$tag,
+    "StringAttr":$name,
+    OptionalParameter<"DIFileAttr">:$file,
+    "uint32_t":$line,
+    OptionalParameter<"DIScopeAttr">:$scope,
+    "uint64_t":$sizeInBits,
+    "uint64_t":$alignInBits,
+    OptionalArrayRefParameter<"DINodeAttr">:$elements
+  );
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DIDerivedTypeAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIDerivedTypeAttr : LLVM_Attr<"DIDerivedType", "di_derived_type", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DITypeAttr"> {
+  let parameters = (ins
+    LLVM_DITagParameter:$tag,
+    "StringAttr":$name,
+    "DITypeAttr":$baseType,
+    "uint64_t":$sizeInBits,
+    "uint32_t":$alignInBits,
+    "uint64_t":$offsetInBits
+  );
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DIFileAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIFileAttr : LLVM_Attr<"DIFile", "di_file", /*traits=*/[], "DIScopeAttr"> {
+  let parameters = (ins "StringAttr":$name, "StringAttr":$directory);
+  let builders = [AttrBuilder<(ins "StringRef":$name, "StringRef":$directory), [{
+      return $_get($_ctxt, StringAttr::get($_ctxt, name),
+                   StringAttr::get($_ctxt, directory));
+    }]>
+  ];
+  let assemblyFormat = "`<` $name `in` $directory `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DILexicalBlockAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DILexicalBlockAttr : LLVM_Attr<"DILexicalBlock", "di_lexical_block", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DIScopeAttr"> {
+  let parameters = (ins
+    "DIScopeAttr":$scope,
+    "DIFileAttr":$file,
+    "unsigned":$line,
+    "unsigned":$column
+  );
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "DIScopeAttr":$scope, "DIFileAttr":$file, "unsigned":$line,
+      "unsigned":$column
+    ), [{
+      return $_get(file.getContext(), scope, file, line, column);
+    }]>
+  ];
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DILexicalBlockFileAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_file", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DIScopeAttr"> {
+  let parameters = (ins
+    "DIScopeAttr":$scope,
+    "DIFileAttr":$file,
+    "unsigned":$descriminator
+  );
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "DIScopeAttr":$scope, "DIFileAttr":$file, "unsigned":$descriminator
+    ), [{
+      return $_get(file.getContext(), scope, file, descriminator);
+    }]>
+  ];
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DILocalVariableAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DINodeAttr"> {
+  let parameters = (ins
+    "DIScopeAttr":$scope,
+    "StringAttr":$name,
+    "DIFileAttr":$file,
+    "unsigned":$line,
+    "unsigned":$arg,
+    "unsigned":$alignInBits,
+    "DITypeAttr":$type
+  );
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "DIScopeAttr":$scope, "StringRef":$name, "DIFileAttr":$file,
+      "unsigned":$line, "unsigned":$arg, "unsigned":$alignInBits,
+      "DITypeAttr":$type
+    ), [{
+      MLIRContext *ctx = file.getContext();
+      return $_get(ctx, scope, StringAttr::get(ctx, name), file, line,
+                   arg, alignInBits, type);
+    }]>
+  ];
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DISubprogramAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DIScopeAttr"> {
+  let parameters = (ins
+    "DICompileUnitAttr":$compileUnit,
+    "DIScopeAttr":$scope,
+    "StringAttr":$name,
+    "StringAttr":$linkageName,
+    "DIFileAttr":$file,
+    "unsigned":$line,
+    "unsigned":$scopeLine,
+    "DISubprogramFlags":$subprogramFlags,
+    "DISubroutineTypeAttr":$type
+  );
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "DICompileUnitAttr":$compileUnit, "DIScopeAttr":$scope, "StringRef":$name,
+      "StringRef":$linkageName, "DIFileAttr":$file, "unsigned":$line, 
+      "unsigned":$scopeLine, "DISubprogramFlags":$subprogramFlags, 
+      "DISubroutineTypeAttr":$type
+    ), [{
+      MLIRContext *ctx = file.getContext();
+      return $_get(ctx, compileUnit, scope, StringAttr::get(ctx, name),
+                   StringAttr::get(ctx, linkageName), file, line,
+                   scopeLine, subprogramFlags, type);
+    }]>
+  ];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DISubrangeAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DISubrangeAttr : LLVM_Attr<"DISubrange", "di_subrange", /*traits=*/[],
+                                    "DINodeAttr"> {
+  let parameters = (ins
+    "IntegerAttr":$count,
+    "IntegerAttr":$lowerBound,
+    "IntegerAttr":$upperBound,
+    "IntegerAttr":$stride
+  );
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DISubroutineTypeAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DISubroutineTypeAttr : LLVM_Attr<"DISubroutineType", "di_subroutine_type", [
+    DeclareAttrInterfaceMethods<SubElementAttrInterface>
+  ], "DITypeAttr"> {
+  let parameters = (ins
+    LLVM_DICallingConventionParameter:$callingConvention,
+    OptionalArrayRefParameter<"DITypeAttr">:$types
+  );
+  let builders = [
+    TypeBuilder<(ins "ArrayRef<DITypeAttr>":$types), [{
+      return $_get($_ctxt, /*callingConvention=*/0, types);
+    }]>
+  ];
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
 #endif // LLVMIR_ATTRDEFS
index 09e2d43..0250935 100644 (file)
@@ -23,6 +23,33 @@ namespace mlir {
 namespace LLVM {
 class LoopOptionsAttrBuilder;
 
+/// This class represents the base attribute for all debug info attributes.
+class DINodeAttr : public Attribute {
+public:
+  using Attribute::Attribute;
+
+  // Support LLVM type casting.
+  static bool classof(Attribute attr);
+};
+
+/// This class represents a LLVM attribute that describes a debug info scope.
+class DIScopeAttr : public DINodeAttr {
+public:
+  using DINodeAttr::DINodeAttr;
+
+  /// Support LLVM type casting.
+  static bool classof(Attribute attr);
+};
+
+/// This class represents a LLVM attribute that describes a debug info type.
+class DITypeAttr : public DINodeAttr {
+public:
+  using DINodeAttr::DINodeAttr;
+
+  /// Support LLVM type casting.
+  static bool classof(Attribute attr);
+};
+
 // Inline the LLVM generated Linkage enum and utility.
 // This is only necessary to isolate the "enum generated code" from the
 // attribute definition itself.
index f22b03f..cfcff87 100644 (file)
@@ -205,6 +205,61 @@ def CConv : DialectAttr<
 }
 
 //===----------------------------------------------------------------------===//
+// DIEmissionKind
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIEmissionNone                : I64EnumAttrCase<"None", 0>;
+def LLVM_DIEmissionFull                : I64EnumAttrCase<"Full", 1>;
+def LLVM_DIEmissionLineTablesOnly      : I64EnumAttrCase<"LineTablesOnly", 2>;
+def LLVM_DIEmissionDebugDirectivesOnly : I64EnumAttrCase<"DebugDirectivesOnly", 3>;
+
+def LLVM_DIEmissionKind : I64EnumAttr<
+    "DIEmissionKind",
+    "LLVM debug emission kind", [
+      LLVM_DIEmissionNone,
+      LLVM_DIEmissionFull,
+      LLVM_DIEmissionLineTablesOnly,
+      LLVM_DIEmissionDebugDirectivesOnly,
+    ]> {
+  let cppNamespace = "::mlir::LLVM";
+}
+
+//===----------------------------------------------------------------------===//
+// DISubprogramFlags
+//===----------------------------------------------------------------------===//
+
+def LLVM_DISPVirtual        : I32BitEnumAttrCaseBit<"Virtual", 0>;
+def LLVM_DISPPureVirtual    : I32BitEnumAttrCaseBit<"PureVirtual", 1>;
+def LLVM_DISPLocalToUnit    : I32BitEnumAttrCaseBit<"LocalToUnit", 2>;
+def LLVM_DISPDefinition     : I32BitEnumAttrCaseBit<"Definition", 3>;
+def LLVM_DISPOptimized      : I32BitEnumAttrCaseBit<"Optimized", 4>;
+def LLVM_DISPPure           : I32BitEnumAttrCaseBit<"Pure", 5>;
+def LLVM_DISPElemental      : I32BitEnumAttrCaseBit<"Elemental", 6>;
+def LLVM_DISPRecursive      : I32BitEnumAttrCaseBit<"Recursive", 7>;
+def LLVM_DISPMainSubprogram : I32BitEnumAttrCaseBit<"MainSubprogram", 8>;
+def LLVM_DISPDeleted        : I32BitEnumAttrCaseBit<"Deleted", 9>;
+def LLVM_DISPObjCDirect     : I32BitEnumAttrCaseBit<"ObjCDirect", 11>;
+
+def DISubprogramFlags : I32BitEnumAttr<
+    "DISubprogramFlags",
+    "LLVM DISubprogram flags", [
+      LLVM_DISPVirtual,
+      LLVM_DISPPureVirtual,
+      LLVM_DISPLocalToUnit,
+      LLVM_DISPDefinition,
+      LLVM_DISPOptimized,
+      LLVM_DISPPure, 
+      LLVM_DISPElemental,
+      LLVM_DISPRecursive,
+      LLVM_DISPMainSubprogram,
+      LLVM_DISPDeleted,
+      LLVM_DISPObjCDirect
+    ]> {
+  let cppNamespace = "::mlir::LLVM";
+  let printBitEnumPrimaryGroups = 1;
+}
+
+//===----------------------------------------------------------------------===//
 // FastmathFlags
 //===----------------------------------------------------------------------===//
 
index a6b47cf..d78efa5 100644 (file)
@@ -3,6 +3,7 @@
 
 include "mlir/IR/OpBase.td"
 include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
+include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
 include "mlir/Interfaces/InferTypeOpInterface.td"
 
 // Operations that correspond to LLVM intrinsics. With MLIR operation set being
@@ -229,6 +230,31 @@ def LLVM_CoroResumeOp : LLVM_IntrOp<"coro.resume", [], [], [], 0> {
 }
 
 //
+// Debug function intrinsics.
+//
+
+def LLVM_DbgAddrOp : LLVM_Op<"dbg.addr"> {
+  let summary = "Describe the current address of a local debug info variable.";
+  let arguments = (ins LLVM_AnyPointer:$addr, LLVM_DILocalVariableAttr:$varInfo);
+
+  let assemblyFormat = "qualified($varInfo) `=` $addr `:` type($addr) attr-dict";
+}
+
+def LLVM_DbgDeclareOp : LLVM_Op<"dbg.declare"> {
+  let summary = "Declare the address of a local debug info variable.";
+  let arguments = (ins LLVM_AnyPointer:$addr, LLVM_DILocalVariableAttr:$varInfo);
+
+  let assemblyFormat = "qualified($varInfo) `=` $addr `:` type($addr) attr-dict";
+}
+
+def LLVM_DbgValueOp : LLVM_Op<"dbg.value"> {
+  let summary = "Describe the current value of a local debug info variable.";
+  let arguments = (ins LLVM_Type:$value, LLVM_DILocalVariableAttr:$varInfo);
+
+  let assemblyFormat = "qualified($varInfo) `=` $value `:` type($value) attr-dict";
+}
+
+//
 // Variadic function intrinsics.
 //
 
index 880e2fa..b3f13ed 100644 (file)
@@ -21,6 +21,7 @@ add_mlir_dialect_library(MLIRLLVMDialect
 
   LINK_COMPONENTS
   AsmParser
+  BinaryFormat
   BitReader
   BitWriter
   Core
index 894b3b2..7d0c229 100644 (file)
@@ -16,6 +16,7 @@
 #include "mlir/IR/DialectImplementation.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/BinaryFormat/Dwarf.h"
 
 using namespace mlir;
 using namespace mlir::LLVM;
@@ -36,6 +37,197 @@ void LLVMDialect::registerAttributes() {
 }
 
 //===----------------------------------------------------------------------===//
+// DINodeAttr
+//===----------------------------------------------------------------------===//
+
+bool DINodeAttr::classof(Attribute attr) {
+  return llvm::isa<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
+                   DIDerivedTypeAttr, DIFileAttr, DILexicalBlockAttr,
+                   DILexicalBlockFileAttr, DILocalVariableAttr,
+                   DISubprogramAttr, DISubroutineTypeAttr>(attr);
+}
+
+//===----------------------------------------------------------------------===//
+// DIScopeAttr
+//===----------------------------------------------------------------------===//
+
+bool DIScopeAttr::classof(Attribute attr) {
+  return llvm::isa<DICompileUnitAttr, DIFileAttr, DILexicalBlockAttr,
+                   DILexicalBlockFileAttr, DISubprogramAttr>(attr);
+}
+
+//===----------------------------------------------------------------------===//
+// DITypeAttr
+//===----------------------------------------------------------------------===//
+
+bool DITypeAttr::classof(Attribute attr) {
+  return llvm::isa<DIBasicTypeAttr, DISubroutineTypeAttr>(attr);
+}
+
+//===----------------------------------------------------------------------===//
+// DICompileUnitAttr
+//===----------------------------------------------------------------------===//
+
+void DICompileUnitAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getFile());
+  walkAttrsFn(getProducer());
+}
+
+Attribute
+DICompileUnitAttr::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
+                                               ArrayRef<Type> replTypes) const {
+  return get(getContext(), getSourceLanguage(), replAttrs[0].cast<DIFileAttr>(),
+             replAttrs[1].cast<StringAttr>(), getIsOptimized(),
+             getEmissionKind());
+}
+
+//===----------------------------------------------------------------------===//
+// DICompositeTypeAttr
+//===----------------------------------------------------------------------===//
+
+void DICompositeTypeAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getName());
+  walkAttrsFn(getFile());
+  walkAttrsFn(getScope());
+  for (DINodeAttr element : getElements())
+    walkAttrsFn(element);
+}
+
+Attribute DICompositeTypeAttr::replaceImmediateSubElements(
+    ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
+  ArrayRef<Attribute> elements = replAttrs.drop_front(3);
+  return get(
+      getContext(), getTag(), replAttrs[0].cast<StringAttr>(),
+      cast_or_null<DIFileAttr>(replAttrs[1]), getLine(),
+      cast_or_null<DIScopeAttr>(replAttrs[2]), getSizeInBits(),
+      getAlignInBits(),
+      ArrayRef<DINodeAttr>(static_cast<const DINodeAttr *>(elements.data()),
+                           elements.size()));
+}
+
+//===----------------------------------------------------------------------===//
+// DIDerivedTypeAttr
+//===----------------------------------------------------------------------===//
+
+void DIDerivedTypeAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getName());
+  walkAttrsFn(getBaseType());
+}
+
+Attribute
+DIDerivedTypeAttr::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
+                                               ArrayRef<Type> replTypes) const {
+  return get(getContext(), getTag(), replAttrs[0].cast<StringAttr>(),
+             replAttrs[1].cast<DITypeAttr>(), getSizeInBits(), getAlignInBits(),
+             getOffsetInBits());
+}
+
+//===----------------------------------------------------------------------===//
+// DILexicalBlockAttr
+//===----------------------------------------------------------------------===//
+
+void DILexicalBlockAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getScope());
+  walkAttrsFn(getFile());
+}
+
+Attribute DILexicalBlockAttr::replaceImmediateSubElements(
+    ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
+  return get(replAttrs[0].cast<DIScopeAttr>(), replAttrs[1].cast<DIFileAttr>(),
+             getLine(), getColumn());
+}
+
+//===----------------------------------------------------------------------===//
+// DILexicalBlockFileAttr
+//===----------------------------------------------------------------------===//
+
+void DILexicalBlockFileAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getScope());
+  walkAttrsFn(getFile());
+}
+
+Attribute DILexicalBlockFileAttr::replaceImmediateSubElements(
+    ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
+  return get(replAttrs[0].cast<DIScopeAttr>(), replAttrs[1].cast<DIFileAttr>(),
+             getDescriminator());
+}
+
+//===----------------------------------------------------------------------===//
+// DILocalVariableAttr
+//===----------------------------------------------------------------------===//
+
+void DILocalVariableAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getScope());
+  walkAttrsFn(getName());
+  walkAttrsFn(getFile());
+  walkAttrsFn(getType());
+}
+
+Attribute DILocalVariableAttr::replaceImmediateSubElements(
+    ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
+  return get(getContext(), replAttrs[0].cast<DIScopeAttr>(),
+             replAttrs[1].cast<StringAttr>(), replAttrs[2].cast<DIFileAttr>(),
+             getLine(), getArg(), getAlignInBits(),
+             replAttrs[3].cast<DITypeAttr>());
+}
+
+//===----------------------------------------------------------------------===//
+// DISubprogramAttr
+//===----------------------------------------------------------------------===//
+
+void DISubprogramAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  walkAttrsFn(getCompileUnit());
+  walkAttrsFn(getScope());
+  walkAttrsFn(getName());
+  walkAttrsFn(getLinkageName());
+  walkAttrsFn(getFile());
+  walkAttrsFn(getType());
+}
+
+Attribute
+DISubprogramAttr::replaceImmediateSubElements(ArrayRef<Attribute> replAttrs,
+                                              ArrayRef<Type> replTypes) const {
+  return get(getContext(), replAttrs[0].cast<DICompileUnitAttr>(),
+             replAttrs[1].cast<DIScopeAttr>(), replAttrs[2].cast<StringAttr>(),
+             replAttrs[3].cast<StringAttr>(), replAttrs[4].cast<DIFileAttr>(),
+             getLine(), getScopeLine(), getSubprogramFlags(),
+             replAttrs[5].cast<DISubroutineTypeAttr>());
+}
+
+//===----------------------------------------------------------------------===//
+// DISubroutineTypeAttr
+//===----------------------------------------------------------------------===//
+
+void DISubroutineTypeAttr::walkImmediateSubElements(
+    function_ref<void(Attribute)> walkAttrsFn,
+    function_ref<void(Type)> walkTypesFn) const {
+  for (DITypeAttr type : getTypes())
+    walkAttrsFn(type);
+}
+
+Attribute DISubroutineTypeAttr::replaceImmediateSubElements(
+    ArrayRef<Attribute> replAttrs, ArrayRef<Type> replTypes) const {
+  return get(
+      getContext(), getCallingConvention(),
+      ArrayRef<DITypeAttr>(static_cast<const DITypeAttr *>(replAttrs.data()),
+                           replAttrs.size()));
+}
+
+//===----------------------------------------------------------------------===//
 // LoopOptionsAttrBuilder
 //===----------------------------------------------------------------------===//
 
index 5476c94..375ec6f 100644 (file)
@@ -2557,6 +2557,28 @@ OpFoldResult LLVM::GEPOp::fold(ArrayRef<Attribute> operands) {
 }
 
 //===----------------------------------------------------------------------===//
+// OpAsmDialectInterface
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface {
+  using OpAsmDialectInterface::OpAsmDialectInterface;
+
+  AliasResult getAlias(Attribute attr, raw_ostream &os) const override {
+    return TypeSwitch<Attribute, AliasResult>(attr)
+        .Case<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
+              DIDerivedTypeAttr, DIFileAttr, DILexicalBlockAttr,
+              DILexicalBlockFileAttr, DILocalVariableAttr, DISubprogramAttr,
+              DISubroutineTypeAttr>([&](auto attr) {
+          os << decltype(attr)::getMnemonic();
+          return AliasResult::OverridableAlias;
+        })
+        .Default([](Attribute) { return AliasResult::NoAlias; });
+  }
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
 // LLVMDialect initialization, type parsing, and registration.
 //===----------------------------------------------------------------------===//
 
@@ -2584,6 +2606,7 @@ void LLVMDialect::initialize() {
 
   // Support unknown operations because not all LLVM operations are registered.
   allowUnknownOperations();
+  addInterfaces<LLVMOpAsmDialectInterface>();
 }
 
 #define GET_OP_CLASSES
diff --git a/mlir/test/Dialect/LLVMIR/debuginfo.mlir b/mlir/test/Dialect/LLVMIR/debuginfo.mlir
new file mode 100644 (file)
index 0000000..5e7401f
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// CHECK: #[[TYPE:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "si64", sizeInBits = 0, encoding = DW_ATE_signed>
+#si64 = #llvm.di_basic_type<
+  tag = DW_TAG_base_type, name = "si64", sizeInBits = 0,
+  encoding = DW_ATE_signed
+>
+
+// CHECK: #[[FILE:.*]] = #llvm.di_file<"debuginfo.mlir" in "/test/">
+#file = #llvm.di_file<"debuginfo.mlir" in "/test/">
+
+// CHECK: #[[CU:.*]] = #llvm.di_compile_unit<sourceLanguage = DW_LANG_C, file = #[[FILE]], producer = "MLIR", isOptimized = true, emissionKind = Full>
+#cu = #llvm.di_compile_unit<
+  sourceLanguage = DW_LANG_C, file = #file, producer = "MLIR",
+  isOptimized = true, emissionKind = Full
+>
+
+// CHECK: #[[SPTYPE:.*]] = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #[[TYPE]]>
+#spType = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #si64>
+
+// CHECK: #[[SP:.*]] = #llvm.di_subprogram<compileUnit = #[[CU]], scope = #[[FILE]], name = "intrinsics", linkageName = "intrinsics", file = #[[FILE]], line = 3, scopeLine = 3, subprogramFlags = "Definition|Optimized", type = #[[SPTYPE]]>
+#sp = #llvm.di_subprogram<
+  compileUnit = #cu, scope = #file, name = "intrinsics", linkageName = "intrinsics",
+  file = #file, line = 3, scopeLine = 3, subprogramFlags = "Definition|Optimized", type = #spType
+>
+
+// CHECK: #[[VAR:.*]] = #llvm.di_local_variable<scope = #[[SP]], name = "arg", file = #[[FILE]], line = 6, arg = 1, alignInBits = 0, type = #[[TYPE]]>
+#variable = #llvm.di_local_variable<scope = #sp, name = "arg", file = #file, line = 6, arg = 1, alignInBits = 0, type = #si64>
+
+// CHECK: llvm.func @intrinsics(%[[ARG:.*]]: i64)
+llvm.func @intrinsics(%arg: i64) {
+  // CHECK: %[[ALLOC:.*]] = llvm.alloca 
+  %allocCount = llvm.mlir.constant(1 : i32) : i32
+  %alloc = llvm.alloca %allocCount x i64 : (i32) -> !llvm.ptr<i64>
+
+  // CHECK: llvm.dbg.value #[[VAR]] = %[[ARG]]
+  // CHECK: llvm.dbg.addr #[[VAR]] = %[[ALLOC]]
+  // CHECK: llvm.dbg.declare #[[VAR]] = %[[ALLOC]]
+  llvm.dbg.value #variable = %arg : i64
+  llvm.dbg.addr #variable = %alloc : !llvm.ptr<i64>
+  llvm.dbg.declare #variable = %alloc : !llvm.ptr<i64>
+  llvm.return
+}