-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Compile compiler-rt with MSVC #28611
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
I suspect this will either optimise less well or be less precise (or both), so maybe it makes sense to have a |
The compiler-rt implementation is pretty similar, so it should optimize just as well unless the platform has a native instruction for it. I can cfg it out to only be used on msvc though. |
unsafe { intrinsics::powif32(self, n) } | ||
let (mut r, mut a) = (1., self); | ||
let mut b = if n < 0 { n.wrapping_neg() as u32 } else { n as u32 }; | ||
loop { |
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.
I would personally prefer this as the following, which is simpler (IMO):
while b != 0 {
if b % 2 != 0 { r *= a }
b /= 2;
a *= a;
}
if n < 0 { r.recip() } else { r }
But I don't feel particularly strongly. (Yes, I know the code as written does an additional a *= a
.)
If you feel strongly about avoiding that extra a *= a
I even prefer this form (i.e. basically just avoid folding the return
into a complicated expression in the loop):
loop {
if b % 2 != 0 { r *= a }
b /= 2;
if b == 0 { break }
a *= a;
}
if n < 0 { r.recip() } else { r }
I'm talking about optimising at a higher level than just codegen, e.g. constant folding/reasoning about variable ranges etc. Also, if it's a similar implementation, that means my precision concern isn't a concern. |
Okay, I switched to using |
Perhaps we should do something like rlibc and continue to emit the opcodes, but instead of linking to
Of course the other option is to get |
Yeah, this works on our current nightlies. You can verify that
Edit: Of course if we do this we lose the ability to just inline the whole thing which happens if we simply don't emit the opcode. |
Is there a compiler flag to set no_compiler_rt? Because if we simply disable compiler_rt from being built immediately then build fails because our stage0 compiler expects compiler_rt to exist. Otherwise the solution is to apply this for one nightly and then actually stop building it the next. |
@angelsl We'd have to wait till the next snapshot, not nightly, to disable compiler-rt from building. |
Bah. I'll just put in my hackfix then. |
I just did a simple test of checking the emitted asm and constant folding seems entirely unaffected, the inline constants in the asm are bit for bit identical. |
Unfortunately I don't think we can take this step just yet. We need a guaranteed way to inform LLVM that it can't lower anything to a call to compiler-rt, otherwise it's likely to pop up from time to time and we'll have to go patch up various implementations here and there as they arise. For example, a 32-bit target requires the fn foo(a: i64, b: i64) -> i64 {
a.checked_mul(b).unwrap_or(0)
} It looks like other commonly used intrinsics from compiler-rt, such as for operations like I agree it'd be nice to not have to build compiler-rt on MSVC, but I don't think it's worth "just hoping" that LLVM doesn't start lowering to any functions in compiler-rt. Another example of that currently LLVM doesn't lower expressions like |
Perhaps instead of avoiding using the intrinsics, we should just write pure Rust implementations of the intrinsics themselves? Considering you can use Clang with MSVC without compiler-rt, it should be entirely feasible for Rust to do so as well. |
Unfortunately even that isn't enough to cut it unless we start linking as all the weird intrinsic names (which they themselves are subject to change). LLVM frequently lowers to new intrinsics or creates instructions later lowered to new intrinsics as the result of optimizations, so we need a way to tell LLVM that it cannot perform these optimizations or lowerings by letting it know the intrinsic functions are not available.
This is good news to know! It should help in learning what they do so we may be able to mirror it. Taking pot shots at the compiler, however, saying "X supports Y, why doesn't Rust" may not be so productive. |
☔ The latest upstream changes (presumably #28668) made this pull request unmergeable. Please resolve the merge conflicts. |
With regards to I doubt LLVM will ever start doing optimizations that lower to intrinsics which msvc doesn't provide since Clang is supposed to work without compiler-rt in the msvc toolchain. Thus it should be enough for us to simply not emit intrinsics which don't have a native instruction or msvc function and just have our own implementation instead. |
Apparently D faced a similar issue and falls back to implementing multiplication with overflow themselves. https://github.com/ldc-developers/druntime/blob/c5a1f3186ffe7e0bcbbcb291d9d0df9c7d668614/src/core/checkedint.d#L584-L600 |
Interesting! I wonder if perhaps if the LLVM folks have much to say about this? LLVM seems to claim that generated code that it should work without compiler-rt, but that seems contradictory given the current situation of how some intrinsics are lowered. It may be worth asking them if there's a precise set of intrinsics that are expected to not work or if there's a set which are intended to only work, and perhaps we can work with that? Inlining implementations where necessary seems fine for now, and we may also want to have them with |
I think LLVM assumes the intrinsics are there, there is a way to set some intrinsics names to I believe if we simply do not emit any Someone on LLVM IRC yesterday said that "in a freestanding environment there are a subset of intrinsics that the user is expected to provide" and that it's documented in GCC, .. but I couldn't find anything. He might have misunderstood. Seems like this part of LLVM is pretty unknown :/ |
Signed-off-by: Peter Atashian <[email protected]>
I decided to instead take the route of just compiling the necessary bits of compiler-rt with MSVC. Only one small change was needed to compiler-rt due to not needing to compile most of it. The changes to the make stuff are rather hairy and I don't really know if they're correct or robust. I hate make and I hope it gets replaced with something much easier to understand. |
Turns out we can't actually tell LLVM to not emit calls to Here you can see that some intrinsics that are not always available are simply set to |
OK, I got compiler-rt builtins compiling on MSVC. Trying to upstream it: http://reviews.llvm.org/D13384 |
Should be merged soon, once I resolve some outstanding issues: link. |
Reviewer is merging the changes. They should be in tomorrow. |
Ah, one thing about The So if we're compiling But if we have to compile LLVM also we have to either build LLVM and then call Someone told me git supports having a submodule within the directory of another submodule (with both submodules of the same parent project) but I haven't tried that out. The other thing is having all this MSVC-specific code so that we use |
Update: I forgot about the intrinsics written in assembly. LLVM's assembler files are in AT&T syntax while MASM only takes Intel notation ... MSBuild silently ignored the assembler files (!) so I didn't account for them until LLVM's buildbots which build with Ninja instead of MSBuild failed. Now I can either choose to port the assembly files to Intel syntax which GAS will accept, or use the C implementations for the functions. Problem with the former is that that would mean LLVM has two different syntaxes for assembly in its source tree which isn't very nice. I'm looking into using the C implementations when building with MSVC. The functions that are affected aren't actually used by Rust at the moment which is why when I tried the builtins library I built with those functions missing it still worked. Alternatively, someone from LLVM said that they're working towards lowering libcalls to the MSVCRT instead. In that case we can continue using MinGW to build builtins until that works. |
All the changes except actually enabling the build on MSVC have been committed into the LLVM tree. You can test it by changing this line to simply There are some builtins for which the code output from C is pretty dismal compared to the handcrafted assembly output. Rust does not use any of them, however. |
Rust currently builds LLVM on Windows by invoking CMake in
So if we do not move Yeah, this sucks. There's no good solution. |
I think it's fine to call cmake as part of the normal build process, this is rarely build and builds quickly so it's not really any skin of anyone's back. |
@alexcrichton Oh, OK then. Will do it the next few days. |
Compiles just the minimal subset of compiler-rt needed for MSVC and it does so using MSVC.
Depends on rust-lang/compiler-rt#10