Skip to content

Fold const bool with unary not#7357

Merged
youknowone merged 2 commits intoRustPython:mainfrom
moreal:const-bool-unary-not
Mar 5, 2026
Merged

Fold const bool with unary not#7357
youknowone merged 2 commits intoRustPython:mainfrom
moreal:const-bool-unary-not

Conversation

@moreal
Copy link
Contributor

@moreal moreal commented Mar 5, 2026

This pull request includes two optimizations:

  • Merges consecutive LOAD_CONST True (or False) and UNARY_NOT into one.
  • Omits TO_BOOL when it follows LOAD_CONST True, as it's redundant.

While the former might not be a common scenario, I believe the latter will be quite useful.


For x = not True, previously, it was compiled into the following lines:

  1           0 RESUME               (0)
              1 LOAD_CONST           (True)
              2 TO_BOOL
              3 CACHE
              4 CACHE
              5 CACHE
              6 UNARY_NOT
              7 STORE_NAME           (0, x)
              8 LOAD_CONST           (None)
              9 RETURN_VALUE

After this pull request, it will be compiled like the following lines:

  1           0 RESUME               (0)
              1 LOAD_CONST           (False)
              2 STORE_NAME           (0, x)
              3 LOAD_CONST           (None)
              4 RETURN_VALUE

Summary by CodeRabbit

  • Optimization

    • Enhanced compiler optimization for boolean operations through improved constant-folding, simplifying boolean expressions into more efficient instruction sequences.
  • Tests

    • Added test coverage for boolean constant handling and boolean negation operations to validate compiler behavior with optimized compilation settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

This pull request adds test scaffolding with optimization-specific helpers and introduces new constant-folding optimization cases for boolean expressions in the IR peephole optimizer.

Changes

Cohort / File(s) Summary
Test Scaffolding
crates/codegen/src/compile.rs
Adds compile_exec_with_options() and compile_exec_optimized() test helpers for running compilation with specific options, plus a new test_const_bool_not_op() test case validating boolean negation constant folding.
Peephole Optimization
crates/codegen/src/ir.rs
Extends constant-folding logic with two new cases: folding LoadConstToBool for boolean constants, and folding LoadConstUnaryNot for boolean constants with value negation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • youknowone
  • ShaharNaveh

Poem

🐰 Constants fold with boolean cheer,
Not ops and conversions disappear!
With optimized tests in place so right,
The peephole shines ever bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fold const bool with unary not' accurately describes the main optimization added - constant folding for boolean constants with unary not operations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@moreal moreal self-assigned this Mar 5, 2026
@moreal moreal requested a review from Copilot March 5, 2026 09:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds targeted peephole optimizations to RustPython’s codegen pipeline to fold boolean-constant not patterns and remove redundant boolean conversions in optimized builds.

Changes:

  • Extend CodeInfo::peephole_optimize to (1) remove TO_BOOL after LOAD_CONST for boolean constants and (2) fold LOAD_CONST <bool> + UNARY_NOT into a single LOAD_CONST <inverted bool>.
  • Add an optimized-compilation test helper and a new snapshot test to validate the optimized bytecode for x = not True.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
crates/codegen/src/ir.rs Implements the peephole folding/removal rules for boolean-constant patterns.
crates/codegen/src/compile.rs Adds compile_exec_optimized and a snapshot test that exercises the new optimization under optimize=1.
crates/codegen/src/snapshots/rustpython_codegen__compile__tests__const_bool_not_op.snap New snapshot asserting the expected optimized disassembly output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@moreal moreal marked this pull request as ready for review March 5, 2026 13:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/codegen/src/compile.rs (1)

9152-9159: Add the complementary not False fold test to lock both constant branches.

Line 9154 currently validates only one side of the bool-negation fold. Adding the False case will better guard regressions in the new peephole rule.

Suggested test addition
 #[test]
 fn test_const_bool_not_op() {
     assert_dis_snapshot!(compile_exec_optimized(
         "\
 x = not True
 "
     ));
 }
+
+#[test]
+fn test_const_bool_not_op_false() {
+    assert_dis_snapshot!(compile_exec_optimized(
+        "\
+x = not False
+"
+    ));
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/compile.rs` around lines 9152 - 9159, Add a new unit test
to complement test_const_bool_not_op that asserts the optimizer folds `not
False` as well as `not True`; specifically create a test (e.g.,
test_const_bool_not_op_false) that calls
assert_dis_snapshot!(compile_exec_optimized("x = not False\n")) so both constant
branches of the bool-negation peephole are covered and locked against
regressions, mirroring the existing test that uses compile_exec_optimized and
assert_dis_snapshot!.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/codegen/src/ir.rs`:
- Around line 705-722: The peephole for (Instruction::LoadConst { consti },
Instruction::UnaryNot) unconditionally inserts a new Boolean constant with the
negated value which can orphan the original co_consts entry; instead, before
calling self.metadata.consts.insert_full, search the constant pool for an
existing ConstantData::Boolean { value: !value } and reuse its index (const_idx)
if found, and only call insert_full when no matching constant exists; update the
returned tuple to use that const_idx so you never create a duplicate orphan
constant (referencing Instruction::LoadConst, Instruction::UnaryNot,
ConstantData::Boolean, self.metadata.consts.insert_full and
remove_unused_consts()/peephole to locate the logic).

---

Nitpick comments:
In `@crates/codegen/src/compile.rs`:
- Around line 9152-9159: Add a new unit test to complement
test_const_bool_not_op that asserts the optimizer folds `not False` as well as
`not True`; specifically create a test (e.g., test_const_bool_not_op_false) that
calls assert_dis_snapshot!(compile_exec_optimized("x = not False\n")) so both
constant branches of the bool-negation peephole are covered and locked against
regressions, mirroring the existing test that uses compile_exec_optimized and
assert_dis_snapshot!.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 42e952a2-d286-4c6e-82ec-7120113ced65

📥 Commits

Reviewing files that changed from the base of the PR and between 5ab631d and 573fe02.

⛔ Files ignored due to path filters (1)
  • crates/codegen/src/snapshots/rustpython_codegen__compile__tests__const_bool_not_op.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs

Comment on lines +705 to +722
(Instruction::LoadConst { consti }, Instruction::UnaryNot) => {
let constant = &self.metadata.consts[consti.get(curr.arg) as usize];
match constant {
ConstantData::Boolean { value } => {
let (const_idx, _) = self
.metadata
.consts
.insert_full(ConstantData::Boolean { value: !value });
Some((
(Instruction::LoadConst {
consti: Arg::marker(),
}),
OpArg::new(const_idx as u32),
))
}
_ => None,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Const-fold inserts can leave dead co_consts entries.

This branch adds a new boolean constant but can orphan the original one. Since remove_unused_consts() runs before peephole, unused constants introduced here are not pruned.

💡 Suggested fix
diff --git a/crates/codegen/src/ir.rs b/crates/codegen/src/ir.rs
@@
         if opts.optimize > 0 {
             self.dce();
             self.peephole_optimize();
+            self.remove_unused_consts();
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/ir.rs` around lines 705 - 722, The peephole for
(Instruction::LoadConst { consti }, Instruction::UnaryNot) unconditionally
inserts a new Boolean constant with the negated value which can orphan the
original co_consts entry; instead, before calling
self.metadata.consts.insert_full, search the constant pool for an existing
ConstantData::Boolean { value: !value } and reuse its index (const_idx) if
found, and only call insert_full when no matching constant exists; update the
returned tuple to use that const_idx so you never create a duplicate orphan
constant (referencing Instruction::LoadConst, Instruction::UnaryNot,
ConstantData::Boolean, self.metadata.consts.insert_full and
remove_unused_consts()/peephole to locate the logic).

@youknowone youknowone merged commit 6f07745 into RustPython:main Mar 5, 2026
36 of 39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants