-
Notifications
You must be signed in to change notification settings - Fork 215
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
__rust_u128_mulo aborts when rhs is zero #367
Comments
I'm going to try fixing this and improving performance. |
edit: With some help, I found the answer to be adding some bounds to the associated types inside the associated types, such as @nagisa I was having trouble using
In practice, these work wonders such as converting this incomprehensible mess:
into this (note: I haven't checked this one for translation bugs because of compilation problems, but I have verified the two traits in other simpler generic implementations)
There is one serious problem that I don't know how to get around, however. I run into this error when I do some computation on a different sized integer and transform it back for the return value:
The type checker doesn't understand that we went in a circle such as The only alternative I know is using a single bikeshedded version of |
You need to add bounds on the associated types, i.e. trait DInt: Int {
type H: HInt<D=Self>;
...
}
trait HInt: Int {
type D: DInt<H=Self>;
...
} Toy example: |
I almost have the divisionless algorithm working, just that the signed versions are giving me extreme trouble with iX::MIN cases. I have run out of the time I can allocate to rust for this week however, so this will need to wait |
I suggest you to copy the algorithm LLVM uses to lower the operation as I implemented in https://reviews.llvm.org/rG73e8a784e62f945a51363c8b5ec4eaedcf9f87e8. |
In particular ( %0 = %LHS.HI != 0 && %RHS.HI != 0
%1 = { iNh, i1 } @umul.with.overflow.iNh(iNh %LHS.HI, iNh %RHS.LO)
%2 = { iNh, i1 } @umul.with.overflow.iNh(iNh %RHS.HI, iNh %LHS.LO)
%3 = mul nuw iN (%LHS.LOW as iN), (%RHS.LOW as iN)
%4 = add iN (%1.0 as iN) << Nh, (%2.0 as iN) << Nh
%5 = { iN, i1 } @uadd.with.overflow.iN( %4, %3 )
%res = { %5.0, %0 || %1.1 || %2.1 || %5.1 } (edit: ah, signed, yeah I had trouble with them too!) |
Is it doing a widening multiplication, and checking if the high part is not zero? That is the fastest way to do it, but only up to the largest widening multiplication supported on an architecture. I have a algorithm based on |
No, none of the operations in this are “widening” in a sense that there are no 256-bit operations involved for a 128-bit UMULO (but there are some simpler 128-bit operations). Here's the algorithm above with types substituted for %0 = %LHS.HI != 0 && %RHS.HI != 0
%1 = { i64, i1 } @umul.with.overflow.i64(i64 %LHS.HI, i64 %RHS.LO)
%2 = { i64, i1 } @umul.with.overflow.i64(i64 %RHS.HI, i64 %LHS.LO)
%3 = mul nuw i128 (%LHS.LOW as i128), (%RHS.LOW as i128) ; note: regular multiplication, can't wrap
%4 = add i128 (%1.0 as i128) << 64, (%2.0 as i128) << 64
%5 = { i128, i1 } @uadd.with.overflow.i128(i128 %4, i128 %3)
%res = { %5.0, %0 || %1.1 || %2.1 || %5.1 } ; res is { i128, i1 } Do note that this is the unsigned version, I couldn't figure out one for signed integers. |
Oh I see what is happening. I will use that instead. |
This is fixed in master now. |
@alexcrichton can a new |
Thanks for the ping! Looks like Amanieu just took care of it a few hours ago, so I'll go ahead and close this. |
compiler-builtins/src/int/mul.rs
Line 78 in 156fcf1
This is not a problem when using cg_llvm, as it is never called. However unlike cg_llvm, cg_clif does use it for the checked u128 multiplication implementation.
cc https://github.com/bjorn3/rustc_codegen_cranelift/issues/1063
The text was updated successfully, but these errors were encountered: