summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorSam Estep <sam@samestep.com>2025-07-23 10:00:24 -0400
committerGitHub <noreply@github.com>2025-07-23 14:00:24 +0000
commit876b21f21cb9bfdff1479364f60f2ce6b15ea0b3 (patch)
tree52ecc56939b737dfbcf82bc802642588d2995334 /source/slang
parented8add13e917eb50a0ab4b021b57191271313a58 (diff)
Add LLDB data formatters for Slang IR (#7828)
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang_lldb.py179
1 files changed, 179 insertions, 0 deletions
diff --git a/source/slang/slang_lldb.py b/source/slang/slang_lldb.py
new file mode 100644
index 000000000..c1213e830
--- /dev/null
+++ b/source/slang/slang_lldb.py
@@ -0,0 +1,179 @@
+"""
+This python script provides LLDB formatters for Slang IR types.
+To use it, add the following line to your ~/.lldbinit file:
+command script import /path/to/source/slang/slang_lldb.py
+"""
+
+import json
+
+import lldb
+
+
+class Children:
+ indices: dict[str, int]
+ values: list[lldb.SBValue]
+
+ def __init__(self):
+ self.indices = {}
+ self.values = []
+
+ def append(self, value: lldb.SBValue) -> None:
+ self.indices[value.name] = len(self.values)
+ self.values.append(value)
+
+ def __len__(self) -> int:
+ return len(self.values)
+
+ def get_index(self, name: str) -> int:
+ return self.indices[name]
+
+ def get_at_index(self, idx: int) -> lldb.SBValue:
+ return self.values[idx]
+
+
+def IRUse_summary(valobj: lldb.SBValue, dict) -> str:
+ val = valobj.GetNonSyntheticValue()
+ return val.GetChildMemberWithName("usedValue").deref.summary
+
+
+class IRInstListBase_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
+ self.valobj = valobj
+
+ def num_children(self):
+ return len(self.children)
+
+ def get_child_index(self, name):
+ return self.children.get_index(name)
+
+ def get_child_at_index(self, idx):
+ return self.children.get_at_index(idx)
+
+ def update(self):
+ self.children = Children()
+ pointer = self.valobj.GetChildMemberWithName("first")
+ i = 0
+ while pointer.unsigned != 0:
+ child = pointer.deref
+ self.children.append(child.Clone(f"[{i}]"))
+ pointer = child.GetNonSyntheticValue().GetChildMemberWithName("next")
+ i += 1
+
+ def has_children(self):
+ return True
+
+
+class IRInst_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
+ self.valobj = valobj
+
+ def num_children(self):
+ return len(self.children)
+
+ def get_child_index(self, name):
+ return self.children.get_index(name)
+
+ def get_child_at_index(self, idx):
+ return self.children.get_at_index(idx)
+
+ def update(self):
+ self.children = Children()
+ target = self.valobj.target
+ ty = self.valobj.type
+ op = self.valobj.GetChildMemberWithName("m_op")
+
+ # literal values
+ value: list[tuple[str, lldb.SBValue]] = []
+ match op.value:
+ case "kIROp_StringLit":
+ string_lit_t = target.FindFirstType("Slang::IRStringLit")
+ string_lit = self.valobj.Cast(string_lit_t)
+ val = string_lit.GetChildMemberWithName("value")
+ value = [("[value]", val.GetChildMemberWithName("stringVal"))]
+ case "kIROp_IntLit":
+ int_lit_t = target.FindFirstType("Slang::IRIntLit")
+ int_lit = self.valobj.Cast(int_lit_t)
+ val = int_lit.GetChildMemberWithName("value")
+ value = [("[value]", val.GetChildMemberWithName("intVal"))]
+
+ # operands
+ operands: list[tuple[str, lldb.SBValue]] = []
+ offset = ty.GetByteSize()
+ ir_use_t = target.FindFirstType("Slang::IRUse")
+ ir_use_size = ir_use_t.GetByteSize()
+ for index in range(self.valobj.GetChildMemberWithName("operandCount").unsigned):
+ name = f"[operand{index}]"
+ operand = self.valobj.CreateChildAtOffset(
+ name, offset + index * ir_use_size, ir_use_t
+ )
+ operands.append((name, operand))
+
+ for name, child in [
+ ("[op]", op),
+ ("[UID]", self.valobj.GetChildMemberWithName("_debugUID")),
+ (
+ "[type]",
+ self.valobj.GetChildMemberWithName("typeUse").GetChildMemberWithName(
+ "usedValue"
+ ),
+ ),
+ # TODO: [exportName]
+ # TODO: [importName]
+ # TODO: [name]
+ *value,
+ *operands,
+ (
+ "[decorations/children]",
+ self.valobj.GetChildMemberWithName("m_decorationsAndChildren"),
+ ),
+ ("[parent]", self.valobj.GetChildMemberWithName("parent")),
+ # TODO: Traverse the linked list to show all uses next to
+ # each other, rather than pointing to the first one.
+ ("[uses]", self.valobj.GetChildMemberWithName("firstUse")),
+ ]:
+ self.children.append(child.Clone(name))
+
+ def has_children(self):
+ return True
+
+
+def IRInst_summary(valobj: lldb.SBValue, dict) -> str:
+ val = valobj.GetNonSyntheticValue()
+ op = val.GetChildMemberWithName("m_op")
+ return f"{{{op.value} {val.address_of.value}}}"
+
+
+def stringval_summary(valobj: lldb.SBValue) -> str:
+ val = valobj.GetNonSyntheticValue()
+ num_chars = val.GetChildMemberWithName("numChars").unsigned
+ chars = val.GetChildMemberWithName("chars").GetPointeeData(0, num_chars).uint8
+ return json.dumps("".join(chr(chars[i]) for i in range(num_chars)))
+
+
+def StringValue_summary(valobj: lldb.SBValue, dict) -> str:
+ return stringval_summary(valobj)
+
+
+def StringSliceValue_summary(valobj: lldb.SBValue, dict) -> str:
+ return stringval_summary(valobj)
+
+
+def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
+ commands = [
+ # Slang::IRUse
+ "type summary add Slang::IRUse -F slang_lldb.IRUse_summary -w slang",
+ # Slang::IRInstListBase
+ "type synthetic add Slang::IRInstListBase -l slang_lldb.IRInstListBase_synthetic -w slang",
+ # Slang::IRInst
+ "type synthetic add Slang::IRInst -l slang_lldb.IRInst_synthetic -w slang",
+ "type summary add --expand Slang::IRInst -F slang_lldb.IRInst_summary -w slang",
+ # Slang::IRConstant::StringValue
+ "type summary add Slang::IRConstant::StringValue -F slang_lldb.StringValue_summary -w slang",
+ # Slang::IRConstant::StringSliceValue
+ "type summary add Slang::IRConstant::StringSliceValue -F slang_lldb.StringSliceValue_summary -w slang",
+ # Enable slang category
+ "type category enable slang",
+ ]
+
+ for c in commands:
+ debugger.HandleCommand(c)