| """ |
| 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::Float4E2M1FNType": '"f4E2M1FN"', |
| "mlir::Float6E2M3FNType": '"f6E2M3FN"', |
| "mlir::Float6E3M2FNType": '"f6E3M2FN"', |
| "mlir::Float8E5M2Type": '"f8E5M2"', |
| "mlir::Float8E4M3Type": '"f8E4M3"', |
| "mlir::Float8E4M3FNType": '"f8E4M3FN"', |
| "mlir::Float8E5M2FNUZType": '"f8E5M2FNUZ"', |
| "mlir::Float8E4M3FNUZType": '"f8E4M3FNUZ"', |
| "mlir::Float8E4M3B11FNUZType": '"f8E4M3B11FNUZ"', |
| "mlir::Float8E3M4Type": '"f8E3M4"', |
| "mlir::Float8E8M0FNUType": '"f8E8M0FNU"', |
| "mlir::BFloat16Type": '"bf16"', |
| "mlir::Float16Type": '"f16"', |
| "mlir::FloatTF32Type": '"tf32"', |
| "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: |
| self.impl_type = None |
| 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") |