From 8b8514eeba99eb81dcfd0fa2b7d570b02ec1e2de Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 00:35:43 +0800 Subject: [PATCH 1/6] bugfix for list extend Signed-off-by: youkaichao --- depyf/decompiler.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/depyf/decompiler.py b/depyf/decompiler.py index 906d463a..be5ae453 100644 --- a/depyf/decompiler.py +++ b/depyf/decompiler.py @@ -1042,9 +1042,8 @@ def LIST_TO_TUPLE(self, inst: Instruction): self.state.stack.append(f"tuple({item})") def LIST_EXTEND(self, inst: Instruction): - assert inst.argval == 1, "Only tested for argval==1" values = self.state.stack.pop() - temp = self.replace_mutable_tos_with_temp() + temp = self.replace_mutable_tos_with_temp(pos=inst.argval) self.state.source_code += f"{temp}.extend({values})\n" def LIST_APPEND(self, inst: Instruction): @@ -1150,11 +1149,12 @@ def get_temp_name(self): Decompiler.temp_count += 1 return f"{self.temp_prefix}{Decompiler.temp_count}" - def replace_mutable_tos_with_temp(self): - ans = self.state.stack.pop() + def replace_mutable_tos_with_temp(self, pos: int = 1): + # pos is basically argval of the instruction + ans = self.state.stack[-pos] temp_name = self.get_temp_name() self.state.source_code += f"{temp_name} = {ans}\n" - self.state.stack.append(temp_name) + self.state.stack[-pos] = temp_name return temp_name @staticmethod From d7d6bc53d42170f0d7871162dd8570fe42d1f2bc Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 01:27:01 +0800 Subject: [PATCH 2/6] update tests Signed-off-by: youkaichao --- tests/test_pytorch/test_no_graph.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/test_pytorch/test_no_graph.py b/tests/test_pytorch/test_no_graph.py index 00a3b45c..a5ba5f06 100644 --- a/tests/test_pytorch/test_no_graph.py +++ b/tests/test_pytorch/test_no_graph.py @@ -2,16 +2,9 @@ @torch.compile def f(x): - s = "Hello" + x - print(s) - -@torch.compile -def g(a, b): - assert a - print(b) - [a for _ in [None]] + s = "hello " + x + return s import depyf with depyf.prepare_debug("./temp_output"): f(", world!") - g(1, 2) From 7d7a9bca0be33c06022cf8c152dda3ce12a0ec20 Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 11:35:48 +0800 Subject: [PATCH 3/6] fix DELETE_SUBSCR Signed-off-by: youkaichao --- depyf/decompiler.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/depyf/decompiler.py b/depyf/decompiler.py index be5ae453..d2fd1c56 100644 --- a/depyf/decompiler.py +++ b/depyf/decompiler.py @@ -300,7 +300,11 @@ def STORE_ATTR(self, inst: Instruction): def DELETE_SUBSCR(self, inst: Instruction): index = self.state.stack.pop() x = self.state.stack.pop() - self.state.source_code += f"del {x}[{index}]\n" + if not f"{x}[{index}]" in self.state.stack: + # if f"{x}[{index}]" already exists somewhere in the stack, + # we don't need to delete it, otherwise that reference will be invalidated. + # TODO: this is a hack, we should use a more robust way to track the references. + self.state.source_code += f"del {x}[{index}]\n" def generic_delete(self, inst: Instruction): self.state.source_code += f"del {inst.argval}\n" From c6d22ce234c25cf46b22ef4343aca1557b693081 Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 11:37:02 +0800 Subject: [PATCH 4/6] resume tests Signed-off-by: youkaichao --- tests/test_pytorch/test_no_graph.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/test_pytorch/test_no_graph.py b/tests/test_pytorch/test_no_graph.py index a5ba5f06..00a3b45c 100644 --- a/tests/test_pytorch/test_no_graph.py +++ b/tests/test_pytorch/test_no_graph.py @@ -2,9 +2,16 @@ @torch.compile def f(x): - s = "hello " + x - return s + s = "Hello" + x + print(s) + +@torch.compile +def g(a, b): + assert a + print(b) + [a for _ in [None]] import depyf with depyf.prepare_debug("./temp_output"): f(", world!") + g(1, 2) From fc3ea7cf800721e6a1e71bd62017ed7ada7d8870 Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 11:48:38 +0800 Subject: [PATCH 5/6] add env var to disable remove_some_temp Signed-off-by: youkaichao --- depyf/decompiler.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/depyf/decompiler.py b/depyf/decompiler.py index d2fd1c56..a13ce81e 100644 --- a/depyf/decompiler.py +++ b/depyf/decompiler.py @@ -1185,8 +1185,13 @@ def decompile( source_code = self.state.source_code # the header might have invalid function name in torchdynamo. only # optimize the function body. - source_code = remove_some_temp( - source_code, self.temp_prefix, indentation) + if os.environ.get("DEPYF_REMOVE_TEMP", "1") == "1": + # remove temp can be dangerous if some code in between contains + # mutation, e.g. as described in https://github.com/thuml/depyf/issues/85 . + # doing a full mutation analysis in python is too complex, so we remove temp by default, + # and only disable it when users set the environment variable DEPYF_REMOVE_TEMP to 0. + source_code = remove_some_temp( + source_code, self.temp_prefix, indentation) header = get_function_signature(self.code, overwite_fn_name) # we cannot rely on `co_names`. For example, `from math import sqrt` will make `math` and `sqrt` in `co_names`. global_names = set(inst.argval for inst in dis.get_instructions(self.code) if inst.opname == "STORE_GLOBAL") From 5f745ee7dda7d2dd22f903f5d7af8395b93e49e8 Mon Sep 17 00:00:00 2001 From: youkaichao Date: Wed, 8 Oct 2025 12:07:22 +0800 Subject: [PATCH 6/6] update tests Signed-off-by: youkaichao --- tests/test_pytorch/test_pytorch.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_pytorch/test_pytorch.py b/tests/test_pytorch/test_pytorch.py index 96773a6f..61141e85 100644 --- a/tests/test_pytorch/test_pytorch.py +++ b/tests/test_pytorch/test_pytorch.py @@ -2,8 +2,7 @@ def toy_function(a, b): x = a / (torch.abs(a) + 1) - if b.sum() < 0: - b = b * -1 + b = b * -1 + b.sum() return x * b class ToyModule(torch.nn.Module): @@ -12,8 +11,7 @@ def __init__(self): def forward(self, a, b): x = a / (torch.abs(a) + 1) - if b.sum() < 0: - b = b * -1 + b = b * -1 + b.sum() return x * b