2022-12-08 12:09:28 +08:00
|
|
|
"""
|
|
|
|
LLDB Formatters for MLIR data types.
|
|
|
|
|
|
|
|
Load into LLDB with 'command script import /path/to/mlirDataFormatters.py'
|
|
|
|
"""
|
|
|
|
|
|
|
|
import re
|
|
|
|
import lldb
|
|
|
|
|
|
|
|
|
|
|
|
def get_expression_path(val: lldb.SBValue):
|
|
|
|
"""Compute the expression path for the given value."""
|
|
|
|
|
|
|
|
stream = lldb.SBStream()
|
|
|
|
if not val.GetExpressionPath(stream):
|
|
|
|
return None
|
|
|
|
return stream.GetData()
|
|
|
|
|
|
|
|
|
|
|
|
def build_ptr_str_from_addr(addrValue: lldb.SBValue, type: lldb.SBType):
|
|
|
|
"""Build a string that computes a pointer using the given address value and type."""
|
|
|
|
|
|
|
|
if type.is_reference:
|
|
|
|
type = type.GetDereferencedType()
|
|
|
|
if not type.is_pointer:
|
|
|
|
type = type.GetPointerType()
|
|
|
|
return f"(({type}){addrValue.GetData().GetUnsignedInt64(lldb.SBError(), 0)})"
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# Attributes and Types
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
# This variable defines various mnemonic strings for use by the builtin
|
|
|
|
# dialect attributes and types, which often have special formatting within
|
|
|
|
# the parser/printer.
|
|
|
|
builtin_attr_type_mnemonics = {
|
|
|
|
"mlir::AffineMapAttr": '"affine_map<...>"',
|
|
|
|
"mlir::ArrayAttr": '"[...]"',
|
|
|
|
"mlir::DenseArray": '"array<...>"',
|
|
|
|
"mlir::DenseResourceElementsAttr": '"dense_resource<...>"',
|
|
|
|
"mlir::DictionaryAttr": '"{...}"',
|
|
|
|
"mlir::IntegerAttr": '"float"',
|
|
|
|
"mlir::IntegerAttr": '"integer"',
|
|
|
|
"mlir::IntegerSetAttr": '"affine_set<...>"',
|
|
|
|
"mlir::SparseElementsAttr": '"sparse<...>"',
|
|
|
|
"mlir::StringAttr": '""...""',
|
|
|
|
"mlir::StridedLayout": '"strided_layout"',
|
|
|
|
"mlir::UnitAttr": '"unit"',
|
|
|
|
"mlir::CallSiteLoc": '"loc(callsite(...))"',
|
|
|
|
"mlir::FusedLoc": '"loc(fused<...>[...])"',
|
|
|
|
"mlir::UnknownLoc": '"loc(unknown)"',
|
|
|
|
"mlir::Float8E5M2Type": '"f8E5M2"',
|
|
|
|
"mlir::Float8E4M3FNType": '"f8E4M3FN"',
|
2023-02-13 22:10:20 +08:00
|
|
|
"mlir::Float8E5M2FNUZType": '"f8E5M2FNUZ"',
|
|
|
|
"mlir::Float8E4M3FNUZType": '"f8E4M3FNUZ"',
|
2022-12-08 12:09:28 +08:00
|
|
|
"mlir::BFloat16Type": '"bf16"',
|
|
|
|
"mlir::Float16Type": '"f16"',
|
|
|
|
"mlir::Float32Type": '"f32"',
|
|
|
|
"mlir::Float64Type": '"f64"',
|
|
|
|
"mlir::Float80Type": '"f80"',
|
|
|
|
"mlir::Float128Type": '"f128"',
|
|
|
|
"mlir::FunctionType": '"(...) -> (...)"',
|
|
|
|
"mlir::IndexType": '"index"',
|
|
|
|
"mlir::IntegerType": '"iN"',
|
|
|
|
"mlir::NoneType": '"none"',
|
|
|
|
"mlir::TupleType": '"tuple<...>"',
|
|
|
|
"mlir::MemRefType": '"memref<...>"',
|
|
|
|
"mlir::UnrankedMemRef": '"memref<...>"',
|
|
|
|
"mlir::UnrankedTensorType": '"tensor<...>"',
|
|
|
|
"mlir::RankedTensorType": '"tensor<...>"',
|
|
|
|
"mlir::VectorType": '"vector<...>"',
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ComputedTypeIDMap:
|
|
|
|
"""Compute a map of type ids to derived attributes, types, and locations.
|
|
|
|
|
|
|
|
This is necessary for determining the C++ type when holding a base class,
|
|
|
|
where we really only have access to dynamic information.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, target: lldb.SBTarget, internal_dict: dict):
|
|
|
|
self.resolved_typeids = {}
|
|
|
|
|
|
|
|
# Find all of the `id` variables, which are the name of TypeID variables
|
|
|
|
# defined within the TypeIDResolver.
|
|
|
|
type_ids = target.FindGlobalVariables("id", lldb.UINT32_MAX)
|
|
|
|
for type_id in type_ids:
|
|
|
|
# Strip out any matches that didn't come from a TypeID resolver. This
|
|
|
|
# also lets us extract the derived type name.
|
|
|
|
name = type_id.GetName()
|
|
|
|
match = re.search("^mlir::detail::TypeIDResolver<(.*), void>::id$", name)
|
|
|
|
if not match:
|
|
|
|
continue
|
|
|
|
type_name = match.group(1)
|
|
|
|
|
|
|
|
# Filter out types that we don't care about.
|
|
|
|
if not type_name.endswith(("Attr", "Loc", "Type")):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Find the LLDB type for the derived type.
|
|
|
|
type = None
|
|
|
|
for typeIt in target.FindTypes(type_name):
|
|
|
|
if not typeIt or not typeIt.IsValid():
|
|
|
|
continue
|
|
|
|
type = typeIt
|
|
|
|
break
|
|
|
|
if not type or not type.IsValid():
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Map the raw address of the type id variable to the LLDB type.
|
|
|
|
self.resolved_typeids[type_id.AddressOf().GetValueAsUnsigned()] = type
|
|
|
|
|
|
|
|
# Resolve the type for the given TypeID address.
|
|
|
|
def resolve_type(self, typeIdAddr: lldb.SBValue):
|
|
|
|
try:
|
|
|
|
return self.resolved_typeids[typeIdAddr.GetValueAsUnsigned()]
|
|
|
|
except KeyError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def is_derived_attribute_or_type(sbtype: lldb.SBType, internal_dict):
|
|
|
|
"""Return if the given type is a derived attribute or type."""
|
|
|
|
|
|
|
|
# We only expect an AttrBase/TypeBase base class.
|
|
|
|
if sbtype.num_bases != 1:
|
|
|
|
return False
|
|
|
|
base_name = sbtype.GetDirectBaseClassAtIndex(0).GetName()
|
|
|
|
return base_name.startswith(("mlir::Attribute::AttrBase", "mlir::Type::TypeBase"))
|
|
|
|
|
|
|
|
|
|
|
|
def get_typeid_map(target: lldb.SBTarget, internal_dict: dict):
|
|
|
|
"""Get or construct a TypeID map for the given target."""
|
|
|
|
|
|
|
|
if "typeIdMap" not in internal_dict:
|
|
|
|
internal_dict["typeIdMap"] = ComputedTypeIDMap(target, internal_dict)
|
|
|
|
return internal_dict["typeIdMap"]
|
|
|
|
|
|
|
|
|
|
|
|
def is_attribute_or_type(sbtype: lldb.SBType, internal_dict):
|
|
|
|
"""Return if the given type is an attribute or type."""
|
|
|
|
|
|
|
|
num_bases = sbtype.GetNumberOfDirectBaseClasses()
|
|
|
|
typeName = sbtype.GetName()
|
|
|
|
|
|
|
|
# We bottom out at Attribute/Type/Location.
|
|
|
|
if num_bases == 0:
|
|
|
|
return typeName in ["mlir::Attribute", "mlir::Type", "mlir::Location"]
|
|
|
|
|
|
|
|
# Check the easy cases of AttrBase/TypeBase.
|
|
|
|
if typeName.startswith(("mlir::Attribute::AttrBase", "mlir::Type::TypeBase")):
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Otherwise, recurse into the base class.
|
|
|
|
return is_attribute_or_type(
|
|
|
|
sbtype.GetDirectBaseClassAtIndex(0).GetType(), internal_dict
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def resolve_attr_type_from_value(
|
|
|
|
valobj: lldb.SBValue, abstractVal: lldb.SBValue, internal_dict
|
|
|
|
):
|
|
|
|
"""Resolve the derived C++ type of an Attribute/Type value."""
|
|
|
|
|
|
|
|
# Derived attribute/types already have the desired type.
|
|
|
|
if is_derived_attribute_or_type(valobj.GetType(), internal_dict):
|
|
|
|
return valobj.GetType()
|
|
|
|
|
|
|
|
# Otherwise, we need to resolve the ImplTy from the TypeID. This is
|
|
|
|
# done dynamically, because we don't use C++ RTTI of any kind.
|
|
|
|
typeIdMap = get_typeid_map(valobj.GetTarget(), internal_dict)
|
|
|
|
return typeIdMap.resolve_type(
|
|
|
|
abstractVal.GetChildMemberWithName("typeID").GetChildMemberWithName("storage")
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class AttrTypeSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for Attributes and Types."""
|
|
|
|
|
|
|
|
def __init__(self, valobj: lldb.SBValue, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
|
|
|
|
# Grab the impl variable, which if this is a Location needs to be
|
|
|
|
# resolved through the LocationAttr impl variable.
|
|
|
|
impl: lldb.SBValue = self.valobj.GetChildMemberWithName("impl")
|
|
|
|
if self.valobj.GetTypeName() == "mlir::Location":
|
|
|
|
impl = impl.GetChildMemberWithName("impl")
|
|
|
|
self.abstractVal = impl.GetChildMemberWithName("abstractType")
|
|
|
|
if not self.abstractVal.IsValid():
|
|
|
|
self.abstractVal = impl.GetChildMemberWithName("abstractAttribute")
|
|
|
|
|
|
|
|
self.type = resolve_attr_type_from_value(
|
|
|
|
valobj, self.abstractVal, internal_dict
|
|
|
|
)
|
|
|
|
if not self.type:
|
|
|
|
return
|
|
|
|
|
|
|
|
# Grab the ImplTy from the resolved type. This is the 3rd template
|
|
|
|
# argument of the base class.
|
|
|
|
self.impl_type = (
|
|
|
|
self.type.GetDirectBaseClassAtIndex(0).GetType().GetTemplateArgumentType(2)
|
|
|
|
)
|
|
|
|
self.impl_pointer_ty = self.impl_type.GetPointerType()
|
|
|
|
self.num_fields = self.impl_type.GetNumberOfFields()
|
|
|
|
|
|
|
|
# Optionally add a mnemonic field.
|
|
|
|
type_name = self.type.GetName()
|
|
|
|
if type_name in builtin_attr_type_mnemonics:
|
|
|
|
self.mnemonic = builtin_attr_type_mnemonics[type_name]
|
|
|
|
elif type_name.startswith("mlir::Dense"):
|
|
|
|
self.mnemonic = "dense<...>"
|
|
|
|
else:
|
|
|
|
self.mnemonic = self.valobj.CreateValueFromExpression(
|
|
|
|
"mnemonic", f"(llvm::StringRef){type_name}::getMnemonic()"
|
|
|
|
)
|
|
|
|
if not self.mnemonic.summary:
|
|
|
|
self.mnemonic = None
|
|
|
|
if self.mnemonic:
|
|
|
|
self.num_fields += 1
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
if not self.impl_type:
|
|
|
|
return 0
|
|
|
|
return self.num_fields
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
if not self.impl_type:
|
|
|
|
return None
|
|
|
|
if self.mnemonic and name == "[mnemonic]":
|
|
|
|
return self.impl_type.GetNumberOfFields()
|
|
|
|
for i in range(self.impl_type.GetNumberOfFields()):
|
|
|
|
if self.impl_type.GetFieldAtIndex(i).GetName() == name:
|
|
|
|
return i
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if not self.impl_type or index >= self.num_fields:
|
|
|
|
return None
|
|
|
|
|
|
|
|
impl: lldb.SBValue = self.valobj.GetChildMemberWithName("impl")
|
|
|
|
impl_ptr: lldb.SBValue = self.valobj.CreateValueFromData(
|
|
|
|
build_ptr_str_from_addr(impl, self.impl_pointer_ty),
|
|
|
|
impl.GetData(),
|
|
|
|
self.impl_pointer_ty,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Check for the mnemonic field.
|
|
|
|
if index == self.impl_type.GetNumberOfFields():
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"[mnemonic]", self.get_mnemonic_string(impl_ptr)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Otherwise, we expect the index to be a field.
|
|
|
|
field: lldb.SBTypeMember = self.impl_type.GetFieldAtIndex(index)
|
|
|
|
|
|
|
|
# Build the field access by resolving through the impl variable.
|
|
|
|
return impl_ptr.GetChildMemberWithName(field.GetName())
|
|
|
|
|
|
|
|
def get_mnemonic_string(self, impl_ptr: lldb.SBValue):
|
|
|
|
if isinstance(self.mnemonic, str):
|
|
|
|
return self.mnemonic
|
|
|
|
|
|
|
|
# If we don't already have the mnemonic in string form, compute
|
|
|
|
# it from the dialect name and the mnemonic.
|
|
|
|
dialect_name = self.abstractVal.GetChildMemberWithName(
|
|
|
|
"dialect"
|
|
|
|
).GetChildMemberWithName("name")
|
|
|
|
self.mnemonic = f'{dialect_name.summary}"."{self.mnemonic.summary}'
|
|
|
|
return self.mnemonic
|
|
|
|
|
|
|
|
|
|
|
|
def AttrTypeSummaryProvider(valobj: lldb.SBValue, internal_dict):
|
|
|
|
"""Define an LLDB summary provider for Attributes and Types."""
|
|
|
|
|
|
|
|
# Check for a value field.
|
|
|
|
value = valobj.GetChildMemberWithName("value")
|
|
|
|
if value and value.summary:
|
|
|
|
return value.summary
|
|
|
|
|
|
|
|
# Otherwise, try the mnemoic.
|
|
|
|
mnemonic: lldb.SBValue = valobj.GetChildMemberWithName("[mnemonic]")
|
|
|
|
if not mnemonic.summary:
|
|
|
|
return ""
|
|
|
|
mnemonicStr = mnemonic.summary.strip('"')
|
|
|
|
|
|
|
|
# Handle a few extremely common builtin attributes/types.
|
|
|
|
## IntegerType
|
|
|
|
if mnemonicStr == "iN":
|
|
|
|
signedness = valobj.GetChildMemberWithName("signedness").GetValueAsUnsigned()
|
|
|
|
prefix = "i"
|
|
|
|
if signedness == 1:
|
|
|
|
prefix = "si"
|
|
|
|
elif signedness == 2:
|
|
|
|
prefix = "ui"
|
|
|
|
return f"{prefix}{valobj.GetChildMemberWithName('width').GetValueAsUnsigned()}"
|
|
|
|
## IntegerAttr
|
|
|
|
if mnemonicStr == "integer":
|
|
|
|
value = valobj.GetChildMemberWithName("value")
|
|
|
|
bitwidth = value.GetChildMemberWithName("BitWidth").GetValueAsUnsigned()
|
|
|
|
if bitwidth <= 64:
|
|
|
|
intVal = (
|
|
|
|
value.GetChildMemberWithName("U")
|
|
|
|
.GetChildMemberWithName("VAL")
|
|
|
|
.GetValueAsUnsigned()
|
|
|
|
)
|
|
|
|
|
|
|
|
if bitwidth == 1:
|
|
|
|
return "true" if intVal else "false"
|
|
|
|
return f"{intVal} : i{bitwidth}"
|
|
|
|
|
|
|
|
return mnemonicStr
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# mlir::Block
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
|
|
|
|
class BlockSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for Blocks."""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
return 3
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
if name == "parent":
|
|
|
|
return 0
|
|
|
|
if name == "operations":
|
|
|
|
return 1
|
|
|
|
if name == "arguments":
|
|
|
|
return 2
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= 3:
|
|
|
|
return None
|
|
|
|
if index == 1:
|
|
|
|
return self.valobj.GetChildMemberWithName("operations")
|
|
|
|
if index == 2:
|
|
|
|
return self.valobj.GetChildMemberWithName("arguments")
|
|
|
|
|
|
|
|
expr_path = build_ptr_str_from_addr(self.valobj, self.valobj.GetType())
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"parent", f"{expr_path}->getParent()"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# mlir::Operation
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
|
|
|
|
def is_op(sbtype: lldb.SBType, internal_dict):
|
|
|
|
"""Return if the given type is an operation."""
|
|
|
|
|
|
|
|
# Bottom out at OpState/Op.
|
|
|
|
typeName = sbtype.GetName()
|
|
|
|
if sbtype.GetNumberOfDirectBaseClasses() == 0:
|
|
|
|
return typeName == "mlir::OpState"
|
|
|
|
if typeName == "mlir::Operation" or typeName.startswith("mlir::Op<"):
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Otherwise, recurse into the base class.
|
|
|
|
return is_op(sbtype.GetDirectBaseClassAtIndex(0).GetType(), internal_dict)
|
|
|
|
|
|
|
|
|
|
|
|
class OperationSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for Operations."""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
self.fields = []
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
return len(self.fields)
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
try:
|
|
|
|
return self.fields.index(name)
|
|
|
|
except ValueError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= len(self.fields):
|
|
|
|
return None
|
|
|
|
name = self.fields[index]
|
|
|
|
if name == "name":
|
|
|
|
return self.opobj.GetChildMemberWithName("name")
|
|
|
|
if name == "parent":
|
|
|
|
return self.opobj.GetChildMemberWithName("block").Clone("parent")
|
|
|
|
if name == "location":
|
|
|
|
return self.opobj.GetChildMemberWithName("location")
|
|
|
|
if name == "attributes":
|
|
|
|
return self.opobj.GetChildMemberWithName("attrs")
|
|
|
|
|
|
|
|
expr_path = build_ptr_str_from_addr(self.opobj, self.opobj.GetType())
|
|
|
|
if name == "operands":
|
|
|
|
return self.opobj.CreateValueFromExpression(
|
|
|
|
"operands", f"{expr_path}->debug_getOperands()"
|
|
|
|
)
|
|
|
|
if name == "results":
|
|
|
|
return self.opobj.CreateValueFromExpression(
|
|
|
|
"results", f"{expr_path}->debug_getResults()"
|
|
|
|
)
|
|
|
|
if name == "successors":
|
|
|
|
return self.opobj.CreateValueFromExpression(
|
|
|
|
"successors", f"{expr_path}->debug_getSuccessors()"
|
|
|
|
)
|
|
|
|
if name == "regions":
|
|
|
|
return self.opobj.CreateValueFromExpression(
|
|
|
|
"regions", f"{expr_path}->debug_getRegions()"
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
# If this is a derived operation, we need to resolve through the
|
|
|
|
# state field.
|
|
|
|
self.opobj = self.valobj
|
|
|
|
if "mlir::Operation" not in self.valobj.GetTypeName():
|
|
|
|
self.opobj = self.valobj.GetChildMemberWithName("state")
|
|
|
|
|
|
|
|
self.fields = ["parent", "name", "location", "attributes"]
|
|
|
|
if (
|
|
|
|
self.opobj.GetChildMemberWithName("hasOperandStorage").GetValueAsUnsigned(0)
|
|
|
|
!= 0
|
|
|
|
):
|
|
|
|
self.fields.append("operands")
|
|
|
|
if self.opobj.GetChildMemberWithName("numResults").GetValueAsUnsigned(0) != 0:
|
|
|
|
self.fields.append("results")
|
|
|
|
if self.opobj.GetChildMemberWithName("numSuccs").GetValueAsUnsigned(0) != 0:
|
|
|
|
self.fields.append("successors")
|
|
|
|
if self.opobj.GetChildMemberWithName("numRegions").GetValueAsUnsigned(0) != 0:
|
|
|
|
self.fields.append("regions")
|
|
|
|
|
|
|
|
|
|
|
|
def OperationSummaryProvider(valobj: lldb.SBValue, internal_dict):
|
|
|
|
"""Define an LLDB summary provider for Operations."""
|
|
|
|
|
|
|
|
name = valobj.GetChildMemberWithName("name")
|
|
|
|
if name and name.summary:
|
|
|
|
return name.summary
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# Ranges
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
|
|
|
|
class DirectRangeSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for direct ranges, i.e. those
|
|
|
|
with a base pointer that points to the type of element we want to display.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
return self.length
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
try:
|
|
|
|
return int(name.lstrip("[").rstrip("]"))
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= self.num_children():
|
|
|
|
return None
|
|
|
|
offset = index * self.type_size
|
|
|
|
return self.data.CreateChildAtOffset(f"[{index}]", offset, self.data_type)
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
length_obj = self.valobj.GetChildMemberWithName("count")
|
|
|
|
self.length = length_obj.GetValueAsUnsigned(0)
|
|
|
|
|
|
|
|
self.data = self.valobj.GetChildMemberWithName("base")
|
|
|
|
self.data_type = self.data.GetType().GetPointeeType()
|
|
|
|
self.type_size = self.data_type.GetByteSize()
|
|
|
|
assert self.type_size != 0
|
|
|
|
|
|
|
|
|
|
|
|
class InDirectRangeSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for ranges
|
|
|
|
that transform the underlying base pointer, e.g. to convert
|
|
|
|
it to a different type depending on various characteristics
|
|
|
|
(e.g. mlir::ValueRange).
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
return self.length
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
try:
|
|
|
|
return int(name.lstrip("[").rstrip("]"))
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= self.num_children():
|
|
|
|
return None
|
|
|
|
expr_path = get_expression_path(self.valobj)
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
f"[{index}]", f"{expr_path}[{index}]"
|
|
|
|
)
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
length_obj = self.valobj.GetChildMemberWithName("count")
|
|
|
|
self.length = length_obj.GetValueAsUnsigned(0)
|
|
|
|
|
|
|
|
|
|
|
|
class IPListRangeSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for an IPList.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
sentinel = self.valobj.GetChildMemberWithName("Sentinel")
|
|
|
|
sentinel_addr = sentinel.AddressOf().GetValueAsUnsigned(0)
|
|
|
|
|
|
|
|
# Iterate the next pointers looking for the sentinel.
|
|
|
|
count = 0
|
|
|
|
current = sentinel.GetChildMemberWithName("Next")
|
|
|
|
while current.GetValueAsUnsigned(0) != sentinel_addr:
|
|
|
|
current = current.GetChildMemberWithName("Next")
|
|
|
|
count += 1
|
|
|
|
|
|
|
|
return count
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
try:
|
|
|
|
return int(name.lstrip("[").rstrip("]"))
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= self.num_children():
|
|
|
|
return None
|
|
|
|
|
|
|
|
# Start from the sentinel and grab the next pointer.
|
|
|
|
value: lldb.SBValue = self.valobj.GetChildMemberWithName("Sentinel")
|
|
|
|
it = 0
|
|
|
|
while it <= index:
|
|
|
|
value = value.GetChildMemberWithName("Next")
|
|
|
|
it += 1
|
|
|
|
|
|
|
|
return value.CreateValueFromExpression(
|
|
|
|
f"[{index}]",
|
|
|
|
f"(({self.value_type})({value.GetTypeName()}){value.GetValueAsUnsigned()})",
|
|
|
|
)
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
self.value_type = (
|
|
|
|
self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType()
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# mlir::Value
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
|
|
|
|
class ValueSynthProvider:
|
|
|
|
"""Define an LLDB synthetic children provider for Values.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, valobj, internal_dict):
|
|
|
|
self.valobj = valobj
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def num_children(self):
|
|
|
|
# 7: BlockArgument:
|
|
|
|
# index, type, owner, firstUse, location
|
|
|
|
if self.kind == 7:
|
|
|
|
return 5
|
|
|
|
|
|
|
|
# 0-6: OpResult:
|
|
|
|
# index, type, owner, firstUse
|
|
|
|
return 4
|
|
|
|
|
|
|
|
def get_child_index(self, name):
|
|
|
|
if name == "index":
|
|
|
|
return 0
|
|
|
|
if name == "type":
|
|
|
|
return 1
|
|
|
|
if name == "owner":
|
|
|
|
return 2
|
|
|
|
if name == "firstUse":
|
|
|
|
return 3
|
|
|
|
if name == "location":
|
|
|
|
return 4
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_child_at_index(self, index):
|
|
|
|
if index >= self.num_children():
|
|
|
|
return None
|
|
|
|
|
|
|
|
# Check if the current value is already an Impl struct.
|
|
|
|
if self.valobj.GetTypeName().endswith("Impl"):
|
|
|
|
impl_ptr_str = build_ptr_str_from_addr(
|
|
|
|
self.valobj.AddressOf(), self.valobj.GetType().GetPointerType()
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
impl = self.valobj.GetChildMemberWithName("impl")
|
|
|
|
impl_ptr_str = build_ptr_str_from_addr(impl, impl.GetType())
|
|
|
|
|
|
|
|
# Cast to the derived Impl type.
|
|
|
|
if self.kind == 7:
|
|
|
|
derived_impl_str = f"((mlir::detail::BlockArgumentImpl *){impl_ptr_str})"
|
|
|
|
elif self.kind == 6:
|
|
|
|
derived_impl_str = f"((mlir::detail::OutOfLineOpResult *){impl_ptr_str})"
|
|
|
|
else:
|
|
|
|
derived_impl_str = f"((mlir::detail::InlineOpResult *){impl_ptr_str})"
|
|
|
|
|
|
|
|
# Handle the shared fields when possible.
|
|
|
|
if index == 1:
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"type", f"{derived_impl_str}->debug_getType()"
|
|
|
|
)
|
|
|
|
if index == 3:
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"firstUse", f"{derived_impl_str}->firstUse"
|
|
|
|
)
|
|
|
|
|
|
|
|
# Handle Block argument children.
|
|
|
|
if self.kind == 7:
|
|
|
|
impl = self.valobj.CreateValueFromExpression("impl", derived_impl_str)
|
|
|
|
if index == 0:
|
|
|
|
return impl.GetChildMemberWithName("index")
|
|
|
|
if index == 2:
|
|
|
|
return impl.GetChildMemberWithName("owner")
|
|
|
|
if index == 4:
|
|
|
|
return impl.GetChildMemberWithName("loc")
|
|
|
|
|
|
|
|
# Handle OpResult children.
|
|
|
|
if index == 0:
|
|
|
|
# Handle the out of line case.
|
|
|
|
if self.kind == 6:
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"index", f"{derived_impl_str}->outOfLineIndex + 6"
|
|
|
|
)
|
|
|
|
return self.valobj.CreateValueFromExpression("index", f"{self.kind}")
|
|
|
|
if index == 2:
|
|
|
|
return self.valobj.CreateValueFromExpression(
|
|
|
|
"owner", f"{derived_impl_str}->getOwner()"
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
# Check if the current value is already an Impl struct.
|
|
|
|
if self.valobj.GetTypeName().endswith("Impl"):
|
|
|
|
impl_ptr_str = build_ptr_str_from_addr(
|
|
|
|
self.valobj, self.valobj.GetType().GetPointerType()
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
impl = self.valobj.GetChildMemberWithName("impl")
|
|
|
|
impl_ptr_str = build_ptr_str_from_addr(impl, impl.GetType())
|
|
|
|
|
|
|
|
# Compute the kind of value we are dealing with.
|
|
|
|
self.kind = self.valobj.CreateValueFromExpression(
|
|
|
|
"kind", f"{impl_ptr_str}->debug_getKind()"
|
|
|
|
).GetValueAsUnsigned()
|
|
|
|
|
|
|
|
|
|
|
|
def ValueSummaryProvider(valobj: lldb.SBValue, internal_dict):
|
|
|
|
"""Define an LLDB summary provider for Values.
|
|
|
|
"""
|
|
|
|
|
|
|
|
index = valobj.GetChildMemberWithName("index").GetValueAsUnsigned()
|
|
|
|
# Check if this is a block argument or not (block arguments have locations).
|
|
|
|
if valobj.GetChildMemberWithName("location").IsValid():
|
|
|
|
summary = f"Block Argument {index}"
|
|
|
|
else:
|
|
|
|
owner_name = (
|
|
|
|
valobj.GetChildMemberWithName("owner")
|
|
|
|
.GetChildMemberWithName("name")
|
|
|
|
.summary
|
|
|
|
)
|
|
|
|
summary = f"{owner_name} Result {index}"
|
|
|
|
|
|
|
|
# Grab the type to help form the summary.
|
|
|
|
type = valobj.GetChildMemberWithName("type")
|
|
|
|
if type.summary:
|
|
|
|
summary += f": {type.summary}"
|
|
|
|
|
|
|
|
return summary
|
|
|
|
|
|
|
|
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
# Initialization
|
|
|
|
# ===----------------------------------------------------------------------=== #
|
|
|
|
|
|
|
|
|
|
|
|
def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
|
|
|
|
cat: lldb.SBTypeCategory = debugger.CreateCategory("mlir")
|
|
|
|
cat.SetEnabled(True)
|
|
|
|
|
|
|
|
# Attributes and Types
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(
|
|
|
|
"mlirDataFormatters.is_attribute_or_type", lldb.eFormatterMatchCallback
|
|
|
|
),
|
|
|
|
lldb.SBTypeSummary.CreateWithFunctionName(
|
|
|
|
"mlirDataFormatters.AttrTypeSummaryProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(
|
|
|
|
"mlirDataFormatters.is_attribute_or_type", lldb.eFormatterMatchCallback
|
|
|
|
),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.AttrTypeSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
# Operation
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier("mlir::Block", lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.BlockSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
# NamedAttribute
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier("mlir::NamedAttribute", lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithSummaryString("${var.name%S} = ${var.value%S}"),
|
|
|
|
)
|
|
|
|
|
|
|
|
# OperationName
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier("mlir::OperationName", lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithSummaryString("${var.impl->name%S}"),
|
|
|
|
)
|
|
|
|
|
|
|
|
# Operation
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(
|
|
|
|
"mlirDataFormatters.is_op", lldb.eFormatterMatchCallback
|
|
|
|
),
|
|
|
|
lldb.SBTypeSummary.CreateWithFunctionName(
|
|
|
|
"mlirDataFormatters.OperationSummaryProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(
|
|
|
|
"mlirDataFormatters.is_op", lldb.eFormatterMatchCallback
|
|
|
|
),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.OperationSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
# Ranges
|
|
|
|
def add_direct_range_summary_and_synth(name):
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithSummaryString("size=${svar%#}"),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.DirectRangeSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
def add_indirect_range_summary_and_synth(name):
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithSummaryString("size=${svar%#}"),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.InDirectRangeSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
def add_iplist_range_summary_and_synth(name):
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithSummaryString("size=${svar%#}"),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.IPListRangeSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
add_direct_range_summary_and_synth("mlir::Operation::operand_range")
|
|
|
|
add_direct_range_summary_and_synth("mlir::OperandRange")
|
|
|
|
add_direct_range_summary_and_synth("mlir::Operation::result_range")
|
|
|
|
add_direct_range_summary_and_synth("mlir::ResultRange")
|
|
|
|
add_direct_range_summary_and_synth("mlir::SuccessorRange")
|
|
|
|
add_indirect_range_summary_and_synth("mlir::ValueRange")
|
|
|
|
add_indirect_range_summary_and_synth("mlir::TypeRange")
|
|
|
|
add_iplist_range_summary_and_synth("mlir::Block::OpListType")
|
|
|
|
add_iplist_range_summary_and_synth("mlir::Region::BlockListType")
|
|
|
|
|
|
|
|
# Values
|
|
|
|
def add_value_summary_and_synth(name):
|
|
|
|
cat.AddTypeSummary(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSummary.CreateWithFunctionName(
|
|
|
|
"mlirDataFormatters.ValueSummaryProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
cat.AddTypeSynthetic(
|
|
|
|
lldb.SBTypeNameSpecifier(name, lldb.eFormatterMatchExact),
|
|
|
|
lldb.SBTypeSynthetic.CreateWithClassName(
|
|
|
|
"mlirDataFormatters.ValueSynthProvider"
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
add_value_summary_and_synth("mlir::BlockArgument")
|
|
|
|
add_value_summary_and_synth("mlir::Value")
|
|
|
|
add_value_summary_and_synth("mlir::OpResult")
|
|
|
|
add_value_summary_and_synth("mlir::detail::OpResultImpl")
|