-
Notifications
You must be signed in to change notification settings - Fork 2.7k
[stdlib] Implement UnsafePointer.__sub__ for signed pointer subtraction #5185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Allows subtraction of pointers with signed integer offsets across SIMD types.
All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA |
- Replace use of .value attribute
@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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
Thanks for the feedback @laszlokindrat and @NathanSWard ! |
Hi @PaulOberg1, please rebase your branch, things should be fixed now. |
@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: |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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)?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
This PR introduces a new signed subtraction method
__ssub__
for UnsafePointer, allowingsubtraction 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