Skip to content

[Dynamo] Support for xor#166065

Closed
jmaczan wants to merge 15 commits intopytorch:mainfrom
jmaczan:146688
Closed

[Dynamo] Support for xor#166065
jmaczan wants to merge 15 commits intopytorch:mainfrom
jmaczan:146688

Conversation

@jmaczan
Copy link
Contributor

@jmaczan jmaczan commented Oct 22, 2025

@pytorch-bot
Copy link

pytorch-bot bot commented Oct 22, 2025

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/166065

Note: Links to docs will display an error until the docs builds have been completed.

✅ You can merge normally! (1 Unrelated Failure)

As of commit 634d52b with merge base 52e744d (image):

UNSTABLE - The following job is marked as unstable, possibly due to flakiness on trunk:

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@pytorch-bot pytorch-bot bot added module: cpu CPU specific problem (e.g., perf, algorithm) module: dynamo release notes: fx release notes category labels Oct 22, 2025
@jmaczan jmaczan changed the title [Dynamo] Support for more binary ops [Dynamo] Support for xor Oct 22, 2025
Copy link
Contributor

@Lucaskabela Lucaskabela left a comment

Choose a reason for hiding this comment

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

This generally looks good but we should add some unit test coverage here and include in summary as testplan :)

@jmaczan
Copy link
Contributor Author

jmaczan commented Oct 24, 2025

@Lucaskabela Added a test! What do you mean with include in summary as testplan?

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

The ValueRange logic seems to have exactly been copied from bitwise_or which seems unlikely.

@jmaczan
Copy link
Contributor Author

jmaczan commented Oct 26, 2025

@ezyang Yes, I didn't understand the concept of upper/lower range analysis, so I tried to use whatever there is for OR and see how tests behave. Now I think I get it and for bitwise xor I try to xor all 4 possible extreme values (lower-lower, lower-upper, upper-lower, upper-upper) and get the lowest of these 4 as lower bound and the highest as upper bound. This works for regular ints. But we can also have infinities and then I don't think we can soundly get a better estimation than -inf/inf, so similarly to bitwise_or I catch an exception and fallback to -inf/inf as bounds

I have some unit tests locally for this, but I don't know where to put them in pytorch, because I didn't see any test file for SymPyValueRangeAnalysis

@ezyang
Copy link
Contributor

ezyang commented Oct 27, 2025

I don't mind having a very bad bound here, fwiw

@jmaczan
Copy link
Contributor Author

jmaczan commented Oct 27, 2025

@ezyang So I think it’s ready to re-review.
Can you run CI tests for me pls (I think I can’t myself yet?)?

@soulitzer soulitzer added the triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module label Oct 28, 2025
MutableMappingVariable,
SetVariable,
UserDefinedDictVariable,
UserDefinedObjectVariable,
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a behavior difference

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct, I have reverted that. I have used call_or as a reference, but seems like I shouldn't


@staticmethod
def xor_(a, b):
return ValueRanges.coordinatewise_increasing_map(a, b, sympy.Xor)
Copy link
Contributor

Choose a reason for hiding this comment

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

Pretty sure this is dead? Also, this is not coordinatewise increasing: 0 ^ 1 = 1, but increasing first coord to 1 gives 1 ^ 1 = 0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed. Instead, in bitwise_xor I directly compute lower and upper when a and b are booleans. I use similar code to what I previously assumed I can use for general case for ints, but here I think it's safe to use

Initially, I didn't dig deep enough when coded it and used or_ as a source of truth and tbh this was just incorrect. xor, unlike or and and is less (not at all?) monotonic, and from what I checked coordinatewise_increasing_map assumes that next values always increase, which is not always a case, as you pointed out

upper_upper = a.upper ^ b.upper

lower = min(lower_lower, lower_upper, upper_lower, upper_upper)
upper = max(lower_lower, lower_upper, upper_lower, upper_upper)
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems unlikely to be right. Please reason through this ChatGPT review:


Counterexample:
• Let a ∈ [8, 15], b ∈ [8, 15].
• Your code checks: 8^8=0, 8^15=7, 15^8=7, 15^15=0 → returns range [0, 7].
• But pick interior values: 10 ^ 5 = 15. The true max is at least 15, so [0, 7] is wrong (too tight).

Other issues:
• With negatives, Python’s unbounded two’s-complement semantics make “bit ranges” tricky; the try/except won’t throw, so you’ll quietly produce misleading bounds.
• Even for non-negative ranges, the minimum isn’t determined by corners either (unless some special structure holds).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ezyang I have underestimated a difficulty of xor. Now I always use the -inf,inf range, unless there are two booleans or both ranges have same lower and upper, respectively (and aren't infinites). As you mentioned some time ago, it's fine to have too wide bound here, so I think that's ok now. At least it's sound

To optimize the ranges further is a bit rabbit hole, and it seems to be possible but chasing it led me to things like Known Bits Analysis in LLVM (https://llvm.org/docs/GlobalISel/KnownBits.html), which sounds exciting, but it's too big and too difficult for me to implement in this PR

Where I can add tests for bitwise_xor? I didn't find a related test file, can I create a new one?

Copy link
Contributor

Choose a reason for hiding this comment

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

You didn't update the bool handling?

Look at test/test_sympy_utils.py

Copy link
Contributor Author

@jmaczan jmaczan Oct 31, 2025

Choose a reason for hiding this comment

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

I've added "bitwise_xor" to be tested in test/test_sympy_utils.py if that's what you're asking about. If that's all we need, then great and pls rereview

@ezyang

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

.

…have their lower and upper equal, get rid of my initially assumpted min/max range and bring back original isinstance args in call_xor (I thought I can reuse these from OR but effectively changed the behavior, so bringing it back as ezyang suggests)
@jmaczan
Copy link
Contributor Author

jmaczan commented Oct 31, 2025

Ready for a rereview

@jmaczan
Copy link
Contributor Author

jmaczan commented Nov 8, 2025

@ezyang Pls re-review

return not vr.is_bool


def is_sympy_integer(value) -> TypeGuard[sympy.Integer]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually should be TypeIs instead of TypeGuard here, we have a stronger invariant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Skylion007 Updated, thanks

@ezyang
Copy link
Contributor

ezyang commented Nov 10, 2025

@pytorchbot merge

@pytorch-bot
Copy link

pytorch-bot bot commented Nov 10, 2025

This PR has pending changes requested. Please address the comments and update the PR before merging.

@jmaczan jmaczan requested a review from Lucaskabela November 10, 2025 07:56
@jmaczan
Copy link
Contributor Author

jmaczan commented Nov 10, 2025

@ezyang pls rerun merge

I fixed the tests - impl works the same way but I don't use sympy bools in min/max because it didn't work (__lt__, le, gt, ge all raise TypeError in sympy Boolean)

The PR can't be merge also because it has requested changes from @Lucaskabela which probably are not applicable anymore

@ezyang
Copy link
Contributor

ezyang commented Nov 11, 2025

@pytorchbot merge

@pytorch-bot pytorch-bot bot added the ciflow/trunk Trigger trunk jobs on your pull request label Nov 11, 2025
@pytorchmergebot
Copy link
Collaborator

Merge started

Your change will be merged once all checks pass (ETA 0-4 Hours).

Learn more about merging in the wiki.

Questions? Feedback? Please reach out to the PyTorch DevX Team

Advanced Debugging
Check the merge workflow status
here

Silv3S pushed a commit to Silv3S/pytorch that referenced this pull request Nov 18, 2025
Add missing support for xor (and maybe some other binary ops later on)

Fixes pytorch#146688

Pull Request resolved: pytorch#166065
Approved by: https://github.com/ezyang
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ciflow/trunk Trigger trunk jobs on your pull request fx Merged module: cpu CPU specific problem (e.g., perf, algorithm) module: dynamo open source release notes: fx release notes category triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Dynamo] Support for more binary ops

8 participants