Currently the compiler has two relatively critical bugs in the implementation of
MSVC unwinding:
* #33112 - faults like segfaults and illegal instructions will run destructors
in Rust, meaning we keep running code after a super-fatal exception
has happened.
* #33116 - When compiling with LTO plus `-Z no-landing-pads` (or `-C
panic=abort` with the previous commit) LLVM won't remove all `invoke`
instructions, meaning that some landing pads stick around and
cleanups may be run due to the previous bug.
These both stem from the flavor of "personality function" that Rust uses for
unwinding on MSVC. On 32-bit this is `_except_handler3` and on 64-bit this is
`__C_specific_handler`, but they both essentially are the "most generic"
personality functions for catching exceptions and running cleanups. That is,
thse two personalities will run cleanups for all exceptions unconditionally, so
when we use them we run cleanups for **all SEH exceptions** (include things like
segfaults).
Note that this also explains why LLVM won't optimize away `invoke` instructions.
These functions can legitimately still unwind (the `nounwind` attribute only
seems to apply to "C++ exception-like unwining"). Also note that the standard
library only *catches* Rust exceptions, not others like segfaults and illegal
instructions.
LLVM has support for another personality, `__CxxFrameHandler3`, which does not
run cleanups for general exceptions, only C++ exceptions thrown by
`_CxxThrowException`. This essentially ideally matches our use case, so this
commit moves us over to using this well-known personality function as well as
exception-throwing function.
This doesn't *seem* to pull in any extra runtime dependencies just yet, but if
it does we can perhaps try to work out how to implement more of it in Rust
rather than relying on MSVCRT runtime bits.
More details about how this is actually implemented can be found in the changes
itself, but this...
Closes#33112Closes#33116
When reuing a definition across codegen units, we obviously cannot use
internal linkage, but using external linkage means that we can end up
with multiple conflicting definitions of a single symbol across
multiple crates. Since the definitions should all be equal
semantically, we can use weak_odr linkage to resolve the situation.
Fixes#32518
We use a 64bit integer to pass the set of attributes that is to be
removed, but the called C function expects a 32bit integer. On most
platforms this doesn't cause any problems other than being unable to
unset some attributes, but on ARM even the lower 32bit aren't handled
correctly because the 64bit value is passed in different registers, so
the C function actually sees random garbage.
So we need to fix the relevant functions to use 32bit integers instead.
Additionally we need an implementation that actually accepts 64bit
integers because some attributes can only be unset that way.
Fixes#32360
Fix floating point fast-math intrinsics
The implementation did not handle the case where both operands were constants, which caused an llvm assertion:
```
rustc: //buildslave//rust-buildbot//slave//nightly-dist-rustc-musl-linux//build//src//llvm//include/llvm/Support/Casting.h:237:
typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::Instruction; Y = llvm::Value; typename llvm::cast_retty<X, Y*>::ret_type = llvm::Instruction*]:
Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
```
`fast` a.k.a UnsafeAlgebra is the flag for enabling all "unsafe"
(according to llvm) float optimizations.
See LangRef for more information http://llvm.org/docs/LangRef.html#fast-math-flags
Providing these operations with less precise associativity rules (for
example) is useful to numerical applications.
For example, the summation loop:
let sum = 0.;
for element in data {
sum += *element;
}
Using the default floating point semantics, this loop expresses the
floats must be added in a sequence, one after another. This constraint
is usually completely unintended, and it means that no autovectorization
is possible.
This commit fixes our support for cross compiling a compiler to run on FreeBSD.
Over the weekend I managed to get a cross compiler from Linux to FreeBSD [1]
which I hope to soon use to start producing FreeBSD nightly compilers. With the
`make dist` support added in #32237 we should be able to produce standard
rustc/rust-std packages for FreeBSD through a new slave with this cross compiler.
Currently, however, we don't "Just Work" when cross compiling FreeBSD and a
number of changes were required (part of this PR). They include:
* A few build fixes were needed in LLVM. Our own branch has been rebased on the
actual 3.8 release and I applied one extra commit [2] which contains two fixes:
1. The LLVM CMake build system passes the `-Wl,-z,defs` flag on many
platforms, but *not* when `CMAKE_SYSTEM_NAME` is "FreeBSD". Unfortunately
this doesn't take into account when we're cross compiling, and as predicted
the build will fail if `-Wl,-z,defs` is passed (see [3] for more info). To
fix this we test `TARGET_TRIPLE` instead of the `CMAKE_SYSTEM_NAME` which
is what we're compiling for which fixes the problem.
2. The `PATH_MAX` constant is apparently defined in a different location than
many other Unix systems, so a file which required this just needed some
help to keep compiling.
* Support for compiling compiler-rt with CMake has been added to rustbuild. It
looks like it just emulates Linux in what it compiles as it didn't seem to
naturally produce anything else... At least the architecture is right, so
seems good for now at least!
[1]: https://github.com/alexcrichton/port-of-rust/blob/master/prebuilt/freebsd/Dockerfile
[2]: https://github.com/rust-lang/llvm/commit/be89e4b5
[3]: https://bugs.webkit.org/show_bug.cgi?id=138420
Hopefully the author caught all the cases. For the mir_dynamic_drops_3 test case the ratio of
memsets to other instructions is 12%. On the other hand we actually do not double drop for at least
the test cases provided anymore in MIR.
This commit rebases our LLVM submodule on the most recent tip of the
`release_38` branch of LLVM. There's been a few fixes and this notably fixes the
assertion error in #31702.
Rust currently emits atomic loads and stores with the LLVM `volatile` qualifier. This is unnecessary and prevents LLVM from performing optimization on these atomic operations.
This commit transitions the compiler to using the new exception handling
instructions in LLVM for implementing unwinding for MSVC. This affects both 32
and 64-bit MSVC as they're both now using SEH-based strategies. In terms of
standard library support, lots more details about how SEH unwinding is
implemented can be found in the commits.
In terms of trans, this change necessitated a few modifications:
* Branches were added to detect when the old landingpad instruction is used or
the new cleanuppad instruction is used to `trans::cleanup`.
* The return value from `cleanuppad` is not stored in an `alloca` (because it
cannot be).
* Each block in trans now has an `Option<LandingPad>` instead of `is_lpad: bool`
for indicating whether it's in a landing pad or not. The new exception
handling intrinsics require that on MSVC each `call` inside of a landing pad
is annotated with which landing pad that it's in. This change to the basic
block means that whenever a `call` or `invoke` instruction is generated we
know whether to annotate it as part of a cleanuppad or not.
* Lots of modifications were made to the instruction builders to construct the
new instructions as well as pass the tagging information for the call/invoke
instructions.
* The translation of the `try` intrinsics for MSVC has been overhauled to use
the new `catchpad` instruction. The filter function is now also a
rustc-generated function instead of a purely libstd-defined function. The
libstd definition still exists, it just has a stable ABI across architectures
and leaves some of the really weird implementation details to the compiler
(e.g. the `localescape` and `localrecover` intrinsics).
This brings some routine upgrades to the bundled LLVM that we're using, the most
notable of which is a bug fix to the way we handle range asserts when loading
the discriminant of an enum. This fix ended up being very similar to f9d4149c
where we basically can't have a range assert when loading a discriminant due to
filling drop, and appropriate flags were added to communicate this to
`trans::adt`.
LLVM was upgraded to a new version in this commit:
f9d4149c29
which was part of this pull request:
https://github.com/rust-lang/rust/issues/26025
Consider the following two lines from that commit:
f9d4149c29 (diff-a3b24dbe2ea7c1981f9ac79f9745f40aL462)f9d4149c29 (diff-a3b24dbe2ea7c1981f9ac79f9745f40aL469)
The purpose of these lines is to register LLVM passes. Prior to the that
commit, the passes being handled were assumed to be ModulePasses (a
specific type of LLVM pass) since they were being added to a ModulePass
manager. After that commit, both lines were refactored (presumably in an
attempt to DRY out the code), but the ModulePasses were changed to be
registered to a FunctionPass manager. This change resulted in
ModulePasses being run, but a Function object was being passed as a
parameter to the pass instead of a Module, which resulted in
segmentation faults.
In this commit, I changed relevant sections of the code to check the
type of the passes being added and register them to the appropriate pass
manager.
Closes https://github.com/rust-lang/rust/issues/31067
Travis CI has new infrastructure using the Google Compute Engine which has both
faster CPUs and more memory, and we've been encouraged to switch as it should
help our build times! The only downside currently, however, is that IPv6 is
disabled, causing a number of standard library tests to fail.
Consequently this commit tweaks our travis config in a few ways:
* ccache is disabled as it's not working on GCE just yet
* Docker is used to run tests inside which reportedly will get IPv6 working
* A system LLVM installation is used instead of building LLVM itself. This is
primarily done to reduce build times, but we want automation for this sort of
behavior anyway and we can extend this in the future with building from source
as well if needed.
* gcc-specific logic is removed as the docker image for Ubuntu gives us a
recent-enough gcc by default.
This commit removes all morestack support from the compiler which entails:
* Segmented stacks are no longer emitted in codegen.
* We no longer build or distribute libmorestack.a
* The `stack_exhausted` lang item is no longer required
The only current use of the segmented stack support in LLVM is to detect stack
overflow. This is no longer really required, however, because we already have
guard pages for all threads and registered signal handlers watching for a
segfault on those pages (to print out a stack overflow message). Additionally,
major platforms (aka Windows) already don't use morestack.
This means that Rust is by default less likely to catch stack overflows because
if a function takes up more than one page of stack space it won't hit the guard
page. This is what the purpose of morestack was (to catch this case), but it's
better served with stack probes which have more cross platform support and no
runtime support necessary. Until LLVM supports this for all platform it looks
like morestack isn't really buying us much.
cc #16012 (still need stack probes)
Closes#26458 (a drive-by fix to help diagnostics on stack overflow)
Currently, `rustc` generates nondeterministic archives, which contain system timestamps. These don't really serve any useful purpose, and enabling deterministic archives moves us a little closer to completely deterministic builds. For a small toy library using `std::ops::{Deref,DerefMut}`, this change actually results in a bit-for-bit identical build every time.
This commit moves the IR files in the distribution, rust_try.ll,
rust_try_msvc_64.ll, and rust_try_msvc_32.ll into the compiler from the main
distribution. There's a few reasons for this change:
* LLVM changes its IR syntax from time to time, so it's very difficult to
have these files build across many LLVM versions simultaneously. We'll likely
want to retain this ability for quite some time into the future.
* The implementation of these files is closely tied to the compiler and runtime
itself, so it makes sense to fold it into a location which can do more
platform-specific checks for various implementation details (such as MSVC 32
vs 64-bit).
* This removes LLVM as a build-time dependency of the standard library. This may
end up becoming very useful if we move towards building the standard library
with Cargo.
In the immediate future, however, this commit should restore compatibility with
LLVM 3.5 and 3.6.
Turns out for OSX our data layout was subtly wrong and the LLVM update must have
exposed this. Instead of fixing this I've removed all data layouts from the
compiler to just use the defaults that LLVM provides for all targets. All data
layouts (and a number of dead modules) are removed from the compiler here.
Custom target specifications can still provide a custom data layout, but it is
now an optional key as the default will be used if one isn't specified.
Updates our LLVM bindings to be able to write out multiple kinds of archives.
This commit also enables using LLVM instead of the system ar on all current
targets.
The C API of this function changed so it no longer takes a personality function.
A shim was introduced to call the right LLVM function (depending on which
version we're compiled against) to set the personality function on the outer
function.
The compiler only ever sets one personality function for all generated
functions, so this should be equivalent.
There's a number of goodies in this LLVM update:
* This contains a fix for https://llvm.org/bugs/show_bug.cgi?id=23957
which should help us bootstrap farther on 32-bit MSVC targets.
* There is better support for writing multiple flavors of archives, allowing us
to use the built-in LLVM support instead of the system `ar` on all current
platforms of the compiler.
* A number of other minor bug fixes and performance improvements to unblock
various other pieces of work.
We have previously always relied upon an external tool, `ar`, to modify archives
that the compiler produces (staticlibs, rlibs, etc). This approach, however, has
a number of downsides:
* Spawning a process is relatively expensive for small compilations
* Encoding arguments across process boundaries often incurs unnecessary overhead
or lossiness. For example `ar` has a tough time dealing with files that have
the same name in archives, and the compiler copies many files around to ensure
they can be passed to `ar` in a reasonable fashion.
* Most `ar` programs found do **not** have the ability to target arbitrary
platforms, so this is an extra tool which needs to be found/specified when
cross compiling.
The LLVM project has had a tool called `llvm-ar` for quite some time now, but it
wasn't available in the standard LLVM libraries (it was just a standalone
program). Recently, however, in LLVM 3.7, this functionality has been moved to a
library and is now accessible by consumers of LLVM via the `writeArchive`
function.
This commit migrates our archive bindings to no longer invoke `ar` by default
but instead make a library call to LLVM to do various operations. This solves
all of the downsides listed above:
* Archive management is now much faster, for example creating a "hello world"
staticlib is now 6x faster (50ms => 8ms). Linking dynamic libraries also
recently started requiring modification of rlibs, and linking a hello world
dynamic library is now 2x faster.
* The compiler is now one step closer to "hassle free" cross compilation because
no external tool is needed for managing archives, LLVM does the right thing!
This commit does not remove support for calling a system `ar` utility currently.
We will continue to maintain compatibility with LLVM 3.5 and 3.6 looking forward
(so the system LLVM can be used wherever possible), and in these cases we must
shell out to a system utility. All nightly builds of Rust, however, will stop
needing a system `ar`.
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
* The `LoopVectorize` option of the LLVM optimization passes has been disabled
as it causes a divide-by-zero exception to happen in LLVM for zero-sized
types. This is reported as https://llvm.org/bugs/show_bug.cgi?id=23763
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
This commit updates the LLVM submodule in use to the current HEAD of the LLVM
repository. This is primarily being done to start picking up unwinding support
for MSVC, which is currently unimplemented in the revision of LLVM we are using.
Along the way a few changes had to be made:
* As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some
significant changes to our RustWrapper.cpp
* As usual, some pass management changed in LLVM, so clang was re-scrutinized to
ensure that we're doing the same thing as clang.
* Some optimization options are now passed directly into the
`PassManagerBuilder` instead of through CLI switches to LLVM.
* The `NoFramePointerElim` option was removed from LLVM, favoring instead the
`no-frame-pointer-elim` function attribute instead.
Additionally, LLVM has picked up some new optimizations which required fixing an
existing soundness hole in the IR we generate. It appears that the current LLVM
we use does not expose this hole. When an enum is moved, the previous slot in
memory is overwritten with a bit pattern corresponding to "dropped". When the
drop glue for this slot is run, however, the switch on the discriminant can
often start executing the `unreachable` block of the switch due to the
discriminant now being outside the normal range. This was patched over locally
for now by having the `unreachable` block just change to a `ret void`.
instead of enumerate the (long) list of platforms to exclude, use only
the short list of platforms to include.
should fixes __morestack symbol problem under openbsd
* Removes `RustJITMemoryManager` from public API.
This was really sort of an implementation detail to begin with.
* `__morestack` is linked to C++ wrapper code and this pointer
is used when resolving the symbol for `ExecutionEngine` code.
* `__morestack_addr` is also resolved for `ExecutionEngine` code.
This function is sometimes referenced in LLVM-generated code,
but was not able to be resolved on Mac OS systems.
* Added Windows support to `ExecutionEngine` API.
* Added a test for basic `ExecutionEngine` functionality.
* Removes `RustJITMemoryManager` from public API.
This was really sort of an implementation detail to begin with.
* `__morestack` is linked to C++ wrapper code and this pointer
is used when resolving the symbol for `ExecutionEngine` code.
* `__morestack_addr` is also resolved for `ExecutionEngine` code.
This function is sometimes referenced in LLVM-generated code,
but was not able to be resolved on Mac OS systems.
* Added Windows support to `ExecutionEngine` API.
* Added a test for basic `ExecutionEngine` functionality.
This commit introduce a third parameter for compatible_ifn!, as new
intrinsics are being added in recent LLVM releases and there is no
need to hardcode a specific case.
Signed-off-by: Luca Bruno <lucab@debian.org>
For imports of constants across DLLs to work on Windows it *requires* that the
import be marked with `dllimport` (unlike functions where the marker is
optional, but strongly recommended). This currently isn't working for importing
FFI constants across boundaries, however, so the one constant exported from
`rustc_llvm.dll` is now a function to be called instead.