[Lldb-commits] [lldb] [lldb][bytecode] Add swift output to Python->bytecode compiler (PR #185773)

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Wed Mar 11 14:52:50 PDT 2026


https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/185773

>From b3827a73789e2ca83853affc072170421e77b163 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 10 Mar 2026 16:11:02 -0700
Subject: [PATCH 1/4] [lldb][bytecode] Add swift output to Python->bytecode
 compiler

---
 lldb/examples/python/formatter_bytecode.py    | 85 +++++++++++++++++--
 ...atter.txt => RigidArrayLLDBFormatterC.txt} |  2 +-
 .../RigidArrayLLDBFormatterSwift.txt          | 38 +++++++++
 .../Python/python-bytecode.test               |  6 +-
 4 files changed, 123 insertions(+), 8 deletions(-)
 rename lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/{RigidArrayLLDBFormatter.txt => RigidArrayLLDBFormatterC.txt} (95%)
 create mode 100644 lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt

diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index dfa6fda0f6402..2cd62480584b0 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -226,6 +226,12 @@ def write_binary(self, output: BinaryIO) -> None:
         output.write(_to_uleb(len(bin)))
         output.write(self._to_binary())
 
+    def write_source(self, output: TextIO, language: str) -> None:
+        if language == "c":
+            self.write_c(output)
+        elif language == "swift":
+            self.write_swift(output)
+
     class _CBuilder:
         """Helper class for emitting binary data as a C-string literal."""
 
@@ -248,7 +254,7 @@ def add_bytes(self, x: bytes, comment: str) -> None:
         def add_string(self, string: str, comment: str) -> None:
             self.entries.append((f'"{string}"', comment))
 
-    def write_source(self, output: TextIO) -> None:
+    def write_c(self, output: TextIO) -> None:
         self.validate()
 
         size = len(self._to_binary())
@@ -281,13 +287,82 @@ def write_source(self, output: TextIO) -> None:
             "__attribute__((used, section(FORMATTER_SECTION)))",
             file=output,
         )
-        print(f"unsigned char _{var_name}_synthetic[] =", file=output)
+        print(f"unsigned char _{var_name}_formatter[] =", file=output)
         indent = "    "
         for string, comment in b.entries:
             print(f"{indent}// {comment}", file=output)
             print(f"{indent}{string}", file=output)
         print(";", file=output)
 
+    class _SwiftBuilder:
+        """Helper class for emitting binary data as a Swift tuple literal."""
+
+        entries: list[Tuple[bytes, str]]
+
+        def __init__(self) -> None:
+            self.entries = []
+
+        def add_byte(self, x: int, comment: str) -> None:
+            self.add_bytes(_to_byte(x), comment)
+
+        def add_uleb(self, x: int, comment: str) -> None:
+            self.add_bytes(_to_uleb(x), comment)
+
+        def add_bytes(self, x: bytes, comment: str) -> None:
+            self.entries.append((x, comment))
+
+        def add_string(self, string: str, comment: str) -> None:
+            self.add_bytes(string.encode(), comment)
+
+        @property
+        def type_decl(self):
+            total_bytes = sum((len(bs) for bs, _ in self.entries))
+            element_list = ", ".join(["UInt8"] * total_bytes)
+            return f"({element_list})"
+
+    def write_swift(self, output: TextIO) -> None:
+        self.validate()
+
+        size = len(self._to_binary())
+
+        builder = self._SwiftBuilder()
+        builder.add_byte(BINARY_VERSION, "version")
+        builder.add_uleb(size, "remaining record size")
+        builder.add_uleb(len(self.type_name), "type name size")
+        builder.add_string(self.type_name, f'type name: "{self.type_name}"')
+        builder.add_byte(self.flags, "flags")
+        for sig, bc in self.signatures:
+            builder.add_byte(SIGNATURES[sig], f"sig_{sig}")
+            builder.add_uleb(len(bc), "program size")
+            builder.add_bytes(bc, "program")
+
+        darwin = ("macOS", "iOS", "watchOS", "tvOS", "visionOS")
+        darwin_list = " || ".join(f"os({_os})" for _os in darwin)
+        print(
+            textwrap.dedent(
+                f"""
+                @used
+                #if {darwin_list}
+                @section("__TEXT,__lldbsummaries")
+                #else
+                @section(".lldbsummaries")
+                #endif
+                """
+            ),
+            file=output,
+        )
+        var_name = re.sub(r"\W", "_", self.type_name)
+        print(
+            f"static let _{var_name}_formatter: {builder.type_decl} = (",
+            file=output,
+        )
+        indent = "    "
+        for bs, comment in builder.entries:
+            print(f"{indent}// {comment}", file=output)
+            byte_list = ", ".join(f"0x{b:02x}" for b in bs)
+            print(f"{indent}{byte_list},", file=output)
+        print(")", file=output)
+
 
 def assemble_file(type_name: str, input: TextIO) -> BytecodeSection:
     input_tokens = _tokenize(input.read())
@@ -1110,7 +1185,7 @@ def _main():
     parser.add_argument(
         "-f",
         "--format",
-        choices=("binary", "c"),
+        choices=("binary", "c", "swift"),
         default="binary",
         help="output file format",
     )
@@ -1133,9 +1208,9 @@ def _main():
         if args.format == "binary":
             with open(args.output, "wb") as output:
                 section.write_binary(output)
-        else:  # args.format == "c"
+        else:
             with open(args.output, "w") as output:
-                section.write_source(output)
+                section.write_source(output, language=args.format)
     elif args.assemble:
         if not args.type_name:
             parser.error("--type-name is required with --assemble")
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatter.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
similarity index 95%
rename from lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatter.txt
rename to lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
index a8daf9e20b85c..dd322077720d7 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatter.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
@@ -6,7 +6,7 @@
 #endif
 
 __attribute__((used, section(FORMATTER_SECTION)))
-unsigned char _RigidArray_synthetic[] =
+unsigned char _RigidArray_formatter[] =
     // version
     "\x01"
     // remaining record size
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
new file mode 100644
index 0000000000000..daf14d35a2d32
--- /dev/null
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
@@ -0,0 +1,38 @@
+
+ at used
+#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
+ at section("__TEXT,__lldbsummaries")
+#else
+ at section(".lldbsummaries")
+#endif
+
+static let _RigidArray_formatter: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
+    // version
+    0x01,
+    // remaining record size
+    0x47,
+    // type name size
+    0x0a,
+    // type name: "RigidArray"
+    0x52, 0x69, 0x67, 0x69, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79,
+    // flags
+    0x00,
+    // sig_update
+    0x05,
+    // program size
+    0x27,
+    // program
+    0x21, 0x00, 0x03, 0x22, 0x08, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x21, 0x00, 0x03, 0x22, 0x06, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x23, 0x21, 0x60,
+    // sig_get_num_children
+    0x02,
+    // program size
+    0x04,
+    // program
+    0x21, 0x02, 0x03, 0x13,
+    // sig_get_child_at_index
+    0x04,
+    // program size
+    0x0a,
+    // program
+    0x21, 0x01, 0x03, 0x21, 0x04, 0x03, 0x23, 0x11, 0x60, 0x13,
+)
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/python-bytecode.test b/lldb/test/Shell/ScriptInterpreter/Python/python-bytecode.test
index 4ed865021e947..82b5ac19bd6db 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/python-bytecode.test
+++ b/lldb/test/Shell/ScriptInterpreter/Python/python-bytecode.test
@@ -1,6 +1,8 @@
 # RUN: mkdir -p %t
-# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --compile %s --format c --type-name RigidArray --output %t/output.txt
-# RUN: diff -u --strip-trailing-cr %S/Inputs/FormatterBytecode/RigidArrayLLDBFormatter.txt %t/output.txt
+# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --compile %s --format c --type-name RigidArray --output %t/c-output.txt
+# RUN: %python %S/../../../../examples/python/formatter_bytecode.py --compile %s --format swift --type-name RigidArray --output %t/swift-output.txt
+# RUN: diff -u --strip-trailing-cr %S/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt %t/c-output.txt
+# RUN: diff -u --strip-trailing-cr %S/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt %t/swift-output.txt
 import lldb
 
 

>From f9e797c679ffc2d7b9572c22472ed42ca360dd90 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 10 Mar 2026 16:56:12 -0700
Subject: [PATCH 2/4] Fix tests, and --assemble

---
 lldb/examples/python/formatter_bytecode.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index 2cd62480584b0..10c29c0813a79 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -1221,9 +1221,9 @@ def _main():
         if args.format == "binary":
             with open(args.output, "wb") as output:
                 section.write_binary(output)
-        else:  # args.format == "c"
+        else:
             with open(args.output, "w") as output:
-                section.write_source(output)
+                section.write_source(output, language=args.format)
     elif args.disassemble:
         if args.output:
             with (
@@ -1317,11 +1317,11 @@ def test_write_source(self):
                 ],
             )
             out = io.StringIO()
-            section.write_source(out)
+            section.write_source(out, language="c")
             src = out.getvalue()
 
             self.assertIn("__attribute__((used, section(FORMATTER_SECTION)))", src)
-            self.assertIn("unsigned char _Account_synthetic[] =", src)
+            self.assertIn("unsigned char _Account_formatter[] =", src)
             self.assertIn('"\\x01"', src)  # version
             self.assertIn('"\\x15"', src)  # record size (21)
             self.assertIn('"\\x07"', src)  # type name size (7)
@@ -1340,7 +1340,7 @@ def test_write_source(self):
 
             # Non-identifier characters in the type name are replaced with '_'.
             out2 = io.StringIO()
-            BytecodeSection("std::vector<int>", 0, []).write_source(out2)
-            self.assertIn("_std__vector_int__synthetic[] =", out2.getvalue())
+            BytecodeSection("std::vector<int>", 0, []).write_source(out2, language="c")
+            self.assertIn("_std__vector_int__formatter[] =", out2.getvalue())
 
     unittest.main(argv=[__file__])

>From 446cc5c44119ae3ddd83f7c2f9ea20f8fe793efc Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 11 Mar 2026 14:20:23 -0700
Subject: [PATCH 3/4] Minor tweaks

---
 lldb/examples/python/formatter_bytecode.py | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index 10c29c0813a79..a49eec2448ce6 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -336,13 +336,11 @@ def write_swift(self, output: TextIO) -> None:
             builder.add_uleb(len(bc), "program size")
             builder.add_bytes(bc, "program")
 
-        darwin = ("macOS", "iOS", "watchOS", "tvOS", "visionOS")
-        darwin_list = " || ".join(f"os({_os})" for _os in darwin)
         print(
             textwrap.dedent(
-                f"""
+                """
                 @used
-                #if {darwin_list}
+                #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
                 @section("__TEXT,__lldbsummaries")
                 #else
                 @section(".lldbsummaries")
@@ -353,7 +351,7 @@ def write_swift(self, output: TextIO) -> None:
         )
         var_name = re.sub(r"\W", "_", self.type_name)
         print(
-            f"static let _{var_name}_formatter: {builder.type_decl} = (",
+            f"let _{var_name}_formatter: {builder.type_decl} = (",
             file=output,
         )
         indent = "    "

>From 10ad3f03f1d02012f7c9c18d982ac59ffcd67ce1 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 11 Mar 2026 14:27:13 -0700
Subject: [PATCH 4/4] Fix section names, and formatting

---
 lldb/examples/python/formatter_bytecode.py             |  9 ++++-----
 .../FormatterBytecode/RigidArrayLLDBFormatterSwift.txt | 10 ++++------
 2 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index a49eec2448ce6..e142c1dbaf536 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -338,14 +338,13 @@ def write_swift(self, output: TextIO) -> None:
 
         print(
             textwrap.dedent(
-                """
-                @used
+                """\
                 #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
-                @section("__TEXT,__lldbsummaries")
+                @section("__DATA_CONST,__lldbformatters")
                 #else
-                @section(".lldbsummaries")
+                @section(".lldbformatters")
                 #endif
-                """
+                @used"""
             ),
             file=output,
         )
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
index daf14d35a2d32..42b5dff8614e6 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
@@ -1,12 +1,10 @@
-
- at used
 #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
- at section("__TEXT,__lldbsummaries")
+ at section("__DATA_CONST,__lldbformatters")
 #else
- at section(".lldbsummaries")
+ at section(".lldbformatters")
 #endif
-
-static let _RigidArray_formatter: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
+ at used
+let _RigidArray_formatter: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
     // version
     0x01,
     // remaining record size



More information about the lldb-commits mailing list