Skip to content

Conversation

PaulOberg1
Copy link

@PaulOberg1 PaulOberg1 commented Aug 17, 2025

This PR introduces a new signed subtraction method __ssub__ for UnsafePointer, allowing
subtraction of pointers using both signed and unsigned integer types.

Additionally, it adds comprehensive tests to validate pointer subtraction behavior:

  • test_pointer_subtraction: basic subtraction using standard integer types.

These changes improve the safety and correctness of pointer arithmetic and ensure
consistent behavior across integer types.

Addresses issue: #5179

- Allows subtraction of pointers with signed integer offsets across SIMD types.
@PaulOberg1 PaulOberg1 requested a review from a team as a code owner August 17, 2025 18:05
Copy link

github-actions bot commented Aug 17, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@PaulOberg1
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

modular-cla-bot bot added a commit to modular/cla that referenced this pull request Aug 17, 2025
@laszlokindrat laszlokindrat self-assigned this Aug 18, 2025
@laszlokindrat
Copy link
Contributor

@PaulOberg1 Thank you for the patch, this looks promising! Seems like there is a genuine compiler error caught by one of the CI jobs; can you please investigate and make sure it's all green before we review in detail?

"""
var element_size = sizeof[T]()
var byte_diff = self - other
return Int(byte_diff / element_size)
Copy link
Contributor

@NathanSWard NathanSWard Aug 18, 2025

Choose a reason for hiding this comment

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

Something to note: by using / the Int.__truediv__(Int) function is called which converts both values to floats and then returns a float which we manually cast back to an Int. I believe you can avoid the int -> conversions completely by using the index.divs operation.

Looking at the llvm ir output here we can avoid the fp <-> si conversions.

Copy link
Author

@PaulOberg1 PaulOberg1 Aug 20, 2025

Choose a reason for hiding this comment

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

Thanks for the insight, Nathan! From what I’ve read, Mojo lowers through MLIR before LLVM, and MLIR already exposes the divs (signed) and divu (unsigned) ops for integer division. Would it make sense here to call that directly instead of using /?

Something along the lines of:

var element_size = sizeof[T]()
var byte_diff = self.address - other.address
return intrinsics.divs(byte_diff, element_size)

That way we’d avoid the intermediate float conversion in the generated LLVM IR, and stay closer to the “raw” integer semantics. Curious if you think that’s overkill compared to keeping / for readability.

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct, we can directly use the

__mlir_op.`index.divs`(element_size.value, byte_diff.value)

@lattner also mentions the LLVM sdiv exact instruction however, I'm unsure how we are able to convert the __mlir_type.index to a type that plays nicely with the llvm instruction. (I was looking at the arith.index_cast mlir dialect but I don't think we have access that that yet).

@PaulOberg1
Copy link
Author

Thanks for the feedback @laszlokindrat and @NathanSWard !
I’ve made several iterations on this and resolved most of the issues, but I’m still hitting some CI/compiler errors I can’t reproduce locally. I’d love a bit of guidance on the best way to resolve these last hurdles so the PR can get green. I’m happy to do the work - just want to make sure I’m heading in the right direction :)

@Ahajha
Copy link
Collaborator

Ahajha commented Aug 20, 2025

Hi @PaulOberg1, please rebase your branch, things should be fixed now.

@laszlokindrat
Copy link
Contributor

@PaulOberg1 this looks good to me, but CI is still failing; can you please rebase and investigate?

@@ -366,6 +366,25 @@ struct UnsafePointer[
"""
return self + (-1 * index(offset))

@always_inline("nodebug")
fn __sub__[T: AnyType](self: UnsafePointer[T], other: UnsafePointer[T]) -> Int:
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reason for restricting the self type here?

Copy link
Author

Choose a reason for hiding this comment

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

Good point, will remove that

The number of elements (of type T) between self and other.
"""
alias element_size = sizeof[T]()
var byte_diff: Int = cast(Int, self) - cast(Int, other)
Copy link
Contributor

Choose a reason for hiding this comment

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

There isn't a cast free function in this module, which is why CI is failing. Also note that we already have a __sub__ overload that works for Indexer instances; can we delegate to that (or the other way around)?

Copy link
Author

Choose a reason for hiding this comment

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

Hmm, not sure how that would work though? I switched this to use builtin.ptrtoint since that seems to be the right way to handle pointer-to-int conversion here.

Copy link
Author

Choose a reason for hiding this comment

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

Also, there is an issue with my local environment so I am having to commit changes in order to test them, hence the delays.

@laszlokindrat laszlokindrat added the waiting for response Needs action/response from contributor before a PR can proceed label Aug 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for response Needs action/response from contributor before a PR can proceed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants