Incorrect Value when assigning list slices using OptimizationLevel::None #315

Closed
opened 2023-09-05 16:33:08 +08:00 by derppening · 8 comments
Collaborator

Reproduction

class A:
	a: int32
	b: bool
	def __init__(self, a: int32, b: bool):
		self.a = a
		self.b = b

@extern
def output_int32_list(x: list[int32]):
	...

def run() -> int32:
	bl = [True, False]

	bl1 = bl[:]
	bl1[1:] = [True]
	output_int32_list([int32(b) for b in bl1])

	bl_1 = [True]
	bl2 = bl[:]
	bl2[1:2:2] = bl_1

	return 0

Python/NAC3 (OptimizationLevel::Default) Output:

[1, 1]

NAC3 (OptimizationLevel::None) Output:

[1, 255]

Changes which do not affect the bug

  • Changing the list assignment into a slice assignment for a single element
-	bl1[1:] = [True]
+	bl1[1:2] = [True]

which will result in

[1, 255]
  • Changing bl2[1:2:2] to bl2[1:2:<n>] where n > 1

Changes which stop the bug from manifesting

  • Direct assignment to bl instead of creating a new list and modifying it
-	bl1 = bl[:]
-	bl1[1:] = [True]
-	output_int32_list([int32(b) for b in bl1])
+	bl[1:] = [True]
+	output_int32_list([int32(b) for b in bl])
  • Decomposition of the list assignment into an element assignment + sublist
-	bl1[1:] = [True]
+	bl1[1] = True
+	bl1 = bl1[:2]
  • Changing bl2[1:2:2] to bl2[1:2:1]
  • Removing bl2[1:2:2] = bl_1

Other Notes

Although this does not affect NAC3 under default settings, it still appears to be a bug worth fixing as this may be a bug in codegen.

## Reproduction ```py class A: a: int32 b: bool def __init__(self, a: int32, b: bool): self.a = a self.b = b @extern def output_int32_list(x: list[int32]): ... def run() -> int32: bl = [True, False] bl1 = bl[:] bl1[1:] = [True] output_int32_list([int32(b) for b in bl1]) bl_1 = [True] bl2 = bl[:] bl2[1:2:2] = bl_1 return 0 ``` Python/NAC3 (`OptimizationLevel::Default`) Output: ``` [1, 1] ``` NAC3 (`OptimizationLevel::None`) Output: ``` [1, 255] ``` ### Changes which do not affect the bug - Changing the list assignment into a slice assignment for a single element ```diff - bl1[1:] = [True] + bl1[1:2] = [True] ``` which will result in ``` [1, 255] ``` - Changing `bl2[1:2:2]` to `bl2[1:2:<n>]` where `n > 1` ### Changes which stop the bug from manifesting - Direct assignment to `bl` instead of creating a new list and modifying it ```diff - bl1 = bl[:] - bl1[1:] = [True] - output_int32_list([int32(b) for b in bl1]) + bl[1:] = [True] + output_int32_list([int32(b) for b in bl]) ``` - Decomposition of the list assignment into an element assignment + sublist ```diff - bl1[1:] = [True] + bl1[1] = True + bl1 = bl1[:2] ``` - Changing `bl2[1:2:2]` to `bl2[1:2:1]` - Removing `bl2[1:2:2] = bl_1` ## Other Notes Although this does not affect NAC3 under default settings, it still appears to be a bug worth fixing as this may be a bug in codegen.
Owner

Where exactly do you set -O?

Where exactly do you set -O?
Author
Collaborator

nac3standalone/demo/src/codegen/mod.rs:236:

-            pass_builder.set_optimization_level(OptimizationLevel::Default);
+            pass_builder.set_optimization_level(OptimizationLevel::None);

I was doing that to debug some IR codegen.

`nac3standalone/demo/src/codegen/mod.rs:236`: ```diff - pass_builder.set_optimization_level(OptimizationLevel::Default); + pass_builder.set_optimization_level(OptimizationLevel::None); ``` I was doing that to debug some IR codegen.
Owner

Okay. Why do you call that -O2/-O0?

Looks like probable broken IR indeed.

Okay. Why do you call that -O2/-O0? Looks like probable broken IR indeed.
Author
Collaborator

Because according to LLVM, None/Less/Default/Aggressive corresponds to -O0/-O1/-O2/-O3 respectively. No worries, I will refer to them by the enum names from now on.

Because according to [LLVM](https://llvm.org/doxygen/CodeGen_8h_source.html), `None`/`Less`/`Default`/`Aggressive` corresponds to `-O0`/`-O1`/`-O2`/`-O3` respectively. No worries, I will refer to them by the enum names from now on.
derppening changed title from Incorrect Value when assigning list slices using -O0 to Incorrect Value when assigning list slices using OptimizationLevel::None 2023-09-05 17:02:29 +08:00
Author
Collaborator

This issue seemed to have gone away using the new pass manager. I guess more investigation is needed to determine whether this is a LLVM bug or NAC3 bug.

This issue seemed to have gone away using the new pass manager. I guess more investigation is needed to determine whether this is a LLVM bug or NAC3 bug.
Owner

Most likely a NAC3 bug (invalid IR emitted). I suggest tracking it down using the old pass manager code.

Most likely a NAC3 bug (invalid IR emitted). I suggest tracking it down using the old pass manager code.
Contributor

Yes; seems like this might potentially be a stack lifetime issue that is just masked by more aggressive optimisations.

For debugging IR issues, using the standalone LLVM tools to run the optimiser/codegen pipeline (opt, or even bugpoint for automation) can be very helpful.

Yes; seems like this might potentially be a stack lifetime issue that is just masked by more aggressive optimisations. For debugging IR issues, using the standalone LLVM tools to run the optimiser/codegen pipeline (`opt`, or even `bugpoint` for automation) can be very helpful.
Author
Collaborator

So I found a much simpler way of reproducing the issue:

@extern
def output_int32_list(x: list[int32]):
	...

def run() -> int32:
	bl = [True, False]
	output_int32_list([int32(b) for b in bl])   # [1, 0]

	bl1 = bl[:]
	output_int32_list([int32(b) for b in bl1])  # [1, 0]

	bl1[1:] = [True]
	output_int32_list([int32(b) for b in bl1])  # [1, 255]
	output_int32_list([int32(b) for b in bl1])  # [1, 0]

	return 0
So I found a much simpler way of reproducing the issue: ```py @extern def output_int32_list(x: list[int32]): ... def run() -> int32: bl = [True, False] output_int32_list([int32(b) for b in bl]) # [1, 0] bl1 = bl[:] output_int32_list([int32(b) for b in bl1]) # [1, 0] bl1[1:] = [True] output_int32_list([int32(b) for b in bl1]) # [1, 255] output_int32_list([int32(b) for b in bl1]) # [1, 0] return 0 ```
sb10q closed this issue 2023-09-25 18:12:46 +08:00
Sign in to join this conversation.
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3#315
No description provided.