-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Partial-stabilize the basics from bigint_helper_methods
#144494
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: master
Are you sure you want to change the base?
Conversation
rustbot has assigned @Mark-Simulacrum. Use |
The only issue I can see is that because I also have no idea whether it'd ever be possible to have "more efficient" codegen for the single-carry version than the double-carry one, since I'm not 100% sure what versions of that operation exist across targets. For example, would it always be able to optimise the following three to the same code?
|
If |
With constant values like that I have every expectation they will, yes. They certainly do in LLVM already, since adding Basically it's like how I don't think we need a dedicated (And of course not adding |
d2dbda0
to
8ac4690
Compare
I guess that my main point was that if we want the two-carry version to be the canonical one, and never want to add the single-carry one, it might be more reasonable to call it |
Hmm, my mental model was different: that it's (Like a |
From that perspective, would I guess that would make sense. |
A conversation on IRLO the other day pushed me to write this up 🙂
This PR proposes a partial stabilization of
bigint_helper_methods
(#85532), focusing on a basic set that hopefully can be non-controversial. Specifically:uN::carrying_add
: uN + uN + bool -> (uN, bool)uN::widening_mul
: uN * uN -> (uN, uN)uN::carrying_mul_add
: uN * uN + uN + uN -> (uN, uN)Why these?
carrying_add
, which doesn't seem that complicated, actually broke in 1.82 (see Fix chainingcarrying_add
s #133674) so we should just offer something fit-for-purpose rather than making people keep up with whatever the secret sauce is today. We also get to do things that users cannot, like have the LLVM version emit operations oni256
in the implementation ofu128::carrying_mul_add
(https://rust.godbolt.org/z/cjG7eKcxd).iN * iN
should give(uN, iN)
) and carries can only happen in one direction (vs questions about whether the carry from-128_u8 + -128_u8
should be considered-1
).carrying_add
is the core full adder primitive for implementing addition.carrying_mul_add
is the core primitive for grade school multiplication (see the example in its docs for why both carries are needed).widening_mul
even though it's not strictly needed (its implementation is justcarrying_mul_add(a, b, 0, 0)
right now) as the simplest way for users to get to cranelift'sumulhi
, RISC-V'sMULHU
, Arm'sUMULL
, etc. (For example, I added an ISLE pattern bytecodealliance/wasmtime@d12e423#diff-2041f67049d5ac3d8f62ea91d3cb45cdb8608d5f5cdab988731ae2addf90ef01 so Cranelift can notice what's happening from the fallback, even if the intrinsics aren't overridden specifically. And on x86 this is one of the simplest possible non-trivial functions https://rust.godbolt.org/z/4oadWKTc1 becauseMUL
puts the results in exactly the registers that the scalar pair result happens to want.)(I did not const-stabilize them in this PR because the fallbacks are using
#[const_trait]
plus there's two new intrinsics involved, so I didn't want to also open those cans of worms here. Given that both intrinsics have fallbacks, and thus don't do anything that can't already be expressed in existing Rust, const-stabilizing these should be straight-forward once the underlying machinery is allowed on stable. But that doesn't need to keep these from being usable at runtime in the mean time.)