Skip to content

Commit

Permalink
[MLIR][LLVM] Support Recursive DITypes (#80251)
Browse files Browse the repository at this point in the history
Following the discussion from [this
thread](https://discourse.llvm.org/t/handling-cyclic-dependencies-in-debug-info/67526/11),
this PR adds support for recursive DITypes.

This PR adds:
1. DIRecursiveTypeAttrInterface: An interface that DITypeAttrs can
implement to indicate that it supports recursion. See full description
in code.
2. Importer & exporter support (The only DITypeAttr that implements the
interface is DICompositeTypeAttr, so the exporter is only implemented
for composites too. There will be two methods that each llvm DI type
that supports mutation needs to implement since there's nothing
general).

---------

Co-authored-by: Tobias Gysi <tobias.gysi@nextsilicon.com>
  • Loading branch information
zyx-billy and gysit committed Mar 15, 2024
1 parent 9a42bdc commit 1e8dad3
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 143 deletions.
8 changes: 4 additions & 4 deletions mlir/include/mlir-c/Dialect/LLVM.h
Expand Up @@ -229,10 +229,10 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIBasicTypeAttrGet(

/// Creates a LLVM DICompositeType attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDICompositeTypeAttrGet(
MlirContext ctx, unsigned int tag, MlirAttribute name, MlirAttribute file,
uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags,
uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements,
MlirAttribute const *elements);
MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name,
MlirAttribute file, uint32_t line, MlirAttribute scope,
MlirAttribute baseType, int64_t flags, uint64_t sizeInBits,
uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements);

/// Creates a LLVM DIDerivedType attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIDerivedTypeAttrGet(
Expand Down
2 changes: 2 additions & 0 deletions mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
Expand Up @@ -29,6 +29,8 @@ add_mlir_doc(LLVMIntrinsicOps LLVMIntrinsicOps Dialects/ -gen-op-doc)
set(LLVM_TARGET_DEFINITIONS LLVMInterfaces.td)
mlir_tablegen(LLVMInterfaces.h.inc -gen-op-interface-decls)
mlir_tablegen(LLVMInterfaces.cpp.inc -gen-op-interface-defs)
mlir_tablegen(LLVMAttrInterfaces.h.inc -gen-attr-interface-decls)
mlir_tablegen(LLVMAttrInterfaces.cpp.inc -gen-attr-interface-defs)
mlir_tablegen(LLVMTypeInterfaces.h.inc -gen-type-interface-decls)
mlir_tablegen(LLVMTypeInterfaces.cpp.inc -gen-type-interface-defs)
add_public_tablegen_target(MLIRLLVMInterfacesIncGen)
Expand Down
42 changes: 31 additions & 11 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
Expand Up @@ -10,6 +10,7 @@
#define LLVMIR_ATTRDEFS

include "mlir/Dialect/LLVMIR/LLVMDialect.td"
include "mlir/Dialect/LLVMIR/LLVMInterfaces.td"
include "mlir/IR/AttrTypeBase.td"
include "mlir/IR/CommonAttrConstraints.td"

Expand Down Expand Up @@ -238,41 +239,43 @@ def LoopAnnotationAttr : LLVM_Attr<"LoopAnnotation", "loop_annotation"> {
//===----------------------------------------------------------------------===//

class LLVM_DIParameter<string summary, string default, string parseName,
string printName = parseName>
string errorCase, string printName = parseName>
: AttrOrTypeParameter<"unsigned", "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;
unsigned tag = llvm::dwarf::get}] # parseName # [{(name);
if (tag == }] # errorCase # [{)
return $_parser.emitError(tagLoc)
<< "invalid debug info }] # summary # [{ name: " << name;
return tag;
}() }];
let printer = "$_printer << llvm::dwarf::" # printName # "String($_self)";
let defaultValue = default;
}

def LLVM_DICallingConventionParameter : LLVM_DIParameter<
"calling convention", /*default=*/"0", "CallingConvention", "Convention"
"calling convention", /*default=*/"0", "CallingConvention", /*errorCase=*/"0",
"Convention"
>;

def LLVM_DIEncodingParameter : LLVM_DIParameter<
"encoding", /*default=*/"0", "AttributeEncoding"
"encoding", /*default=*/"0", "AttributeEncoding", /*errorCase=*/"0"
>;

def LLVM_DILanguageParameter : LLVM_DIParameter<
"language", /*default=*/"", "Language"
"language", /*default=*/"", "Language", /*errorCase=*/"0"
>;

def LLVM_DITagParameter : LLVM_DIParameter<
"tag", /*default=*/"", "Tag"
"tag", /*default=*/"", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid"
>;

def LLVM_DIOperationEncodingParameter : LLVM_DIParameter<
"operation encoding", /*default=*/"", "OperationEncoding"
"operation encoding", /*default=*/"", "OperationEncoding", /*errorCase=*/"0"
>;

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -357,9 +360,11 @@ def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
//===----------------------------------------------------------------------===//

def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
/*traits=*/[], "DITypeAttr"> {
[LLVM_DIRecursiveTypeAttrInterface],
"DITypeAttr"> {
let parameters = (ins
LLVM_DITagParameter:$tag,
OptionalParameter<"DistinctAttr">:$recId,
OptionalParameter<"StringAttr">:$name,
OptionalParameter<"DIFileAttr">:$file,
OptionalParameter<"uint32_t">:$line,
Expand All @@ -371,6 +376,21 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
OptionalArrayRefParameter<"DINodeAttr">:$elements
);
let assemblyFormat = "`<` struct(params) `>`";
let extraClassDeclaration = [{
/// Requirements of DIRecursiveTypeAttrInterface.
/// @{

/// Get whether this attr describes a recursive self reference.
bool isRecSelf() { return getTag() == 0; }

/// Get a copy of this type attr but with the recursive ID set to `recId`.
DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId);

/// Build a rec-self instance using the provided `recId`.
static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);

/// @}
}];
}

//===----------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
Expand Up @@ -84,6 +84,8 @@ using linkage::Linkage;
} // namespace LLVM
} // namespace mlir

#include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.h.inc"

#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.h.inc"

Expand Down
56 changes: 55 additions & 1 deletion mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines op and type interfaces for the LLVM dialect in MLIR.
// This file defines interfaces for the LLVM dialect in MLIR.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -319,4 +319,58 @@ def LLVM_PointerElementTypeInterface
];
}

//===----------------------------------------------------------------------===//
// LLVM dialect attr interfaces.
//===----------------------------------------------------------------------===//

def LLVM_DIRecursiveTypeAttrInterface
: AttrInterface<"DIRecursiveTypeAttrInterface"> {
let description = [{
This attribute represents a DITypeAttr that is recursive. Only DITypeAttrs
that translate to LLVM DITypes that support mutation should implement this
interface.

There are two modes for conforming attributes:

1. "rec-decl":
- This attr is a recursive declaration identified by a recId.

2. "rec-self":
- This attr is considered a recursive self reference.
- This attr itself is a placeholder type that should be conceptually
replaced with the closest parent attr of the same type with the same
recId.

For example, to represent a linked list struct:

#rec_self = di_composite_type<recId = 0>
#ptr = di_derived_type<baseType: #rec_self, ...>
#field = di_derived_type<name = "next", baseType: #ptr, ...>
#rec = di_composite_type<recId = 0, name = "Node", elements: #field, ...>
#var = di_local_variable<type = #rec, ...>

Note that a rec-self without an outer rec-decl with the same recId is
conceptually the same as an "unbound" variable. The context needs to provide
meaning to the rec-self.
}];
let cppNamespace = "::mlir::LLVM";
let methods = [
InterfaceMethod<[{
Get whether this attr describes a recursive self reference.
}], "bool", "isRecSelf", (ins)>,
InterfaceMethod<[{
Get the recursive ID used for matching "rec-decl" with "rec-self".
If this attr instance is not recursive, return a null attribute.
}], "DistinctAttr", "getRecId", (ins)>,
InterfaceMethod<[{
Get a copy of this type attr but with the recursive ID set to `recId`.
}], "DIRecursiveTypeAttrInterface", "withRecId",
(ins "DistinctAttr":$recId)>,
StaticInterfaceMethod<[{
Build a rec-self instance using the provided `recId`.
}], "DIRecursiveTypeAttrInterface", "getRecSelf",
(ins "DistinctAttr":$recId)>
];
}

#endif // LLVMIR_INTERFACES
16 changes: 8 additions & 8 deletions mlir/lib/CAPI/Dialect/LLVM.cpp
Expand Up @@ -152,18 +152,18 @@ MlirAttribute mlirLLVMDIBasicTypeAttrGet(MlirContext ctx, unsigned int tag,
}

MlirAttribute mlirLLVMDICompositeTypeAttrGet(
MlirContext ctx, unsigned int tag, MlirAttribute name, MlirAttribute file,
uint32_t line, MlirAttribute scope, MlirAttribute baseType, int64_t flags,
uint64_t sizeInBits, uint64_t alignInBits, intptr_t nElements,
MlirAttribute const *elements) {
MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name,
MlirAttribute file, uint32_t line, MlirAttribute scope,
MlirAttribute baseType, int64_t flags, uint64_t sizeInBits,
uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements) {
SmallVector<Attribute> elementsStorage;
elementsStorage.reserve(nElements);

return wrap(DICompositeTypeAttr::get(
unwrap(ctx), tag, cast<StringAttr>(unwrap(name)),
cast<DIFileAttr>(unwrap(file)), line, cast<DIScopeAttr>(unwrap(scope)),
cast<DITypeAttr>(unwrap(baseType)), DIFlags(flags), sizeInBits,
alignInBits,
unwrap(ctx), tag, cast<DistinctAttr>(unwrap(recId)),
cast<StringAttr>(unwrap(name)), cast<DIFileAttr>(unwrap(file)), line,
cast<DIScopeAttr>(unwrap(scope)), cast<DITypeAttr>(unwrap(baseType)),
DIFlags(flags), sizeInBits, alignInBits,
llvm::map_to_vector(unwrapList(nElements, elements, elementsStorage),
[](Attribute a) { return a.cast<DINodeAttr>(); })));
}
Expand Down
19 changes: 19 additions & 0 deletions mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
Expand Up @@ -35,6 +35,7 @@ static LogicalResult parseExpressionArg(AsmParser &parser, uint64_t opcode,
static void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
ArrayRef<uint64_t> args);

#include "mlir/Dialect/LLVMIR/LLVMAttrInterfaces.cpp.inc"
#include "mlir/Dialect/LLVMIR/LLVMOpsEnums.cpp.inc"
#define GET_ATTRDEF_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
Expand Down Expand Up @@ -185,6 +186,24 @@ void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
});
}

//===----------------------------------------------------------------------===//
// DICompositeTypeAttr
//===----------------------------------------------------------------------===//

DIRecursiveTypeAttrInterface
DICompositeTypeAttr::withRecId(DistinctAttr recId) {
return DICompositeTypeAttr::get(getContext(), getTag(), recId, getName(),
getFile(), getLine(), getScope(),
getBaseType(), getFlags(), getSizeInBits(),
getAlignInBits(), getElements());
}

DIRecursiveTypeAttrInterface
DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
return DICompositeTypeAttr::get(recId.getContext(), 0, recId, {}, {}, 0, {},
{}, DIFlags(), 0, 0, {});
}

//===----------------------------------------------------------------------===//
// TargetFeaturesAttr
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 1e8dad3

Please sign in to comment.