Bring back div_rem
Tracking issue for https://github.com/rust-lang/rfcs/pull/850
cc @quantheory
Any update on this? :)
Shall it avoid giving negative remainders unlike %?
When you divide -1234 by 10, your remainder is -4.
I think the advantage of div_rem is that the computer is already doing both at once, it's just throwing away part of the work instead of instead of letting us keep both parts.
What exactly would it need to push this forward?
@dignifiedquire I'd just write a PR against https://github.com/rust-lang/rust/ and then T-libs can decide what to do.
Make sure to spec it as const from the start (for integers at least)
Edit: oh crap no const-if yet, nevermind i guess
I want to add a set of uX::wrapping_div_rem(lhs, rhs) -> (uX, uX) functions as a way to guarantee that __udivmodti4 and the like are called, and not have to rely on the compiler backend to combine operations. However, someone encountered an LLVM error where the target sparc-unknown-linux-gnu cannot lower any function that returns a tuple of two u128s. If the function were added, wouldn't that completely break 32-bit SPARC targets unless the LLVM issue is resolved?
I'd imagine rustc could add a workaround to do the return lowering in rustc if the LLVM bug is not easy to fix or we want to support old LLVM versions.
Is there someone who wants to tackle the problem? I might try myself, although I have no idea where to begin. I've never messed with code lowering before.
It seems to work fine from clang: https://gcc.godbolt.org/z/8xbrWE
I don't know if it's useful, but I have compiled the following code and generated the corresponding LLVM IR:
#[no_mangle]
fn test_128(one: u128, two: u128) -> (u128, u128) {
let division = one / two;
(division + 40000000, division - 100000)
}
The LLVM IR is:
; Function Attrs: minsize nounwind optsize
define { i128, i128 } @test_128(i128 %one, i128 %two) unnamed_addr #0 {
start:
%_6 = icmp eq i128 %two, 0
br i1 %_6, label %panic, label %bb1, !prof !1, !misexpect !2
bb1: ; preds = %start
%division = udiv i128 %one, %two
%_7 = add i128 %division, 40000000
%_9 = add i128 %division, -100000
%0 = insertvalue { i128, i128 } undef, i128 %_7, 0
%1 = insertvalue { i128, i128 } %0, i128 %_9, 1
ret { i128, i128 } %1
NOTE: I have removed the panic block since I believe it shouldn't be what is causing the error.
The error output generated by rustc is:
LLVM ERROR: unable to allocate function return #6
I have generated the LLVM IR with the flag --emit=llvm-ir. The equivalent function in LLVM IR generated from clang is here.
Thanks a lot!
I would like to point out that div_rem methods may have value even without intrinsic functions to implement them.
- Most importantly, the methods might just help with convenience or readability.
- The standard library is always compiled with opt-level=3, so the optimization will exist even in debug mode.
- There is a little bit of room for optimization outside of the intrinsics. Ex: wrapping_div_rem_euclid()
Since the compiler doesn't recognize the hard coded div function, ethnum-rs has a set of div_rem methods analogous to the integer methods in the standard library. I suggest taking a look at the API and documentation as an example of what the div_rem methods could look like. The implementing code itself isn't as applicable because there were different intrinsics to work with.