mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Switch to rust-lang-nursery/compiler-builtins
This commit migrates the in-tree `libcompiler_builtins` to the upstream version at https://github.com/rust-lang-nursery/compiler-builtins. The upstream version has a number of intrinsics written in Rust and serves as an in-progress rewrite of compiler-rt into Rust. Additionally it also contains all the existing intrinsics defined in `libcompiler_builtins` for 128-bit integers. It's been the intention since the beginning to make this transition but previously it just lacked the manpower to get done. As this PR likely shows it wasn't a trivial integration! Some highlight changes are: * The PR rust-lang-nursery/compiler-builtins#166 contains a number of fixes across platforms and also some refactorings to make the intrinsics easier to read. The additional testing added there also fixed a number of integration issues when pulling the repository into this tree. * LTO with the compiler-builtins crate was fixed to link in the entire crate after the LTO process as these intrinsics are excluded from LTO. * Treatment of hidden symbols was updated as previously the `#![compiler_builtins]` crate would mark all symbol *imports* as hidden whereas it was only intended to mark *exports* as hidden.
This commit is contained in:
parent
1d2db7b9e8
commit
7e6c9f3635
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -2,9 +2,6 @@
|
||||
path = src/llvm
|
||||
url = https://github.com/rust-lang/llvm.git
|
||||
branch = master
|
||||
[submodule "src/compiler-rt"]
|
||||
path = src/compiler-rt
|
||||
url = https://github.com/rust-lang/compiler-rt.git
|
||||
[submodule "src/rt/hoedown"]
|
||||
path = src/rt/hoedown
|
||||
url = https://github.com/rust-lang/hoedown.git
|
||||
@ -33,3 +30,6 @@
|
||||
[submodule "src/tools/rls"]
|
||||
path = src/tools/rls
|
||||
url = https://github.com/rust-lang-nursery/rls.git
|
||||
[submodule "src/libcompiler_builtins"]
|
||||
path = src/libcompiler_builtins
|
||||
url = https://github.com/rust-lang-nursery/compiler-builtins
|
||||
|
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
@ -273,7 +273,6 @@ dependencies = [
|
||||
name = "compiler_builtins"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -142,6 +142,11 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let crate_name = args.windows(2)
|
||||
.find(|a| &*a[0] == "--crate-name")
|
||||
.unwrap();
|
||||
let crate_name = &*crate_name[1];
|
||||
|
||||
// If we're compiling specifically the `panic_abort` crate then we pass
|
||||
// the `-C panic=abort` option. Note that we do not do this for any
|
||||
// other crate intentionally as this is the only crate for now that we
|
||||
@ -150,9 +155,7 @@ fn main() {
|
||||
// This... is a bit of a hack how we detect this. Ideally this
|
||||
// information should be encoded in the crate I guess? Would likely
|
||||
// require an RFC amendment to RFC 1513, however.
|
||||
let is_panic_abort = args.windows(2)
|
||||
.any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort");
|
||||
if is_panic_abort {
|
||||
if crate_name == "panic_abort" {
|
||||
cmd.arg("-C").arg("panic=abort");
|
||||
}
|
||||
|
||||
@ -167,7 +170,15 @@ fn main() {
|
||||
Ok(s) => if s == "true" { "y" } else { "n" },
|
||||
Err(..) => "n",
|
||||
};
|
||||
|
||||
// The compiler builtins are pretty sensitive to symbols referenced in
|
||||
// libcore and such, so we never compile them with debug assertions.
|
||||
if crate_name == "compiler_builtins" {
|
||||
cmd.arg("-C").arg("debug-assertions=no");
|
||||
} else {
|
||||
cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
|
||||
}
|
||||
|
||||
if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
|
||||
cmd.arg("-C").arg(format!("codegen-units={}", s));
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ class RustBuild(object):
|
||||
(self.get_toml('jemalloc') or
|
||||
self.get_mk('CFG_JEMALLOC_ROOT'))))]
|
||||
run(["git", "submodule", "update",
|
||||
"--init"] + submodules,
|
||||
"--init", "--recursive"] + submodules,
|
||||
cwd=self.rust_root, verbose=self.verbose)
|
||||
run(["git", "submodule", "-q", "foreach", "git",
|
||||
"reset", "-q", "--hard"],
|
||||
|
@ -564,10 +564,10 @@ pub fn rust_src(build: &Build) {
|
||||
"src/libstd",
|
||||
"src/libstd_unicode",
|
||||
"src/libunwind",
|
||||
"src/rustc/compiler_builtins_shim",
|
||||
"src/rustc/libc_shim",
|
||||
"src/libtest",
|
||||
"src/libterm",
|
||||
"src/compiler-rt",
|
||||
"src/jemalloc",
|
||||
"src/libprofiler_builtins",
|
||||
];
|
||||
|
@ -239,7 +239,10 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler
|
||||
),
|
||||
_ => return Err(()),
|
||||
};
|
||||
native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path)
|
||||
native_lib_boilerplate("libcompiler_builtins/compiler-rt",
|
||||
sanitizer_name,
|
||||
&link_name,
|
||||
search_path)
|
||||
}
|
||||
|
||||
fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
|
||||
|
@ -67,13 +67,14 @@ for module in $modules; do
|
||||
mv "src/llvm-$commit" src/llvm
|
||||
continue
|
||||
fi
|
||||
if [ ! -d "$cache_src_dir/$module" ]; then
|
||||
if [ ! -e "$cache_src_dir/$module/.git" ]; then
|
||||
echo "WARNING: $module not found in pristine repo"
|
||||
retry sh -c "git submodule deinit -f $module && git submodule update --init $module"
|
||||
retry sh -c "git submodule deinit -f $module && \
|
||||
git submodule update --init --recursive $module"
|
||||
continue
|
||||
fi
|
||||
retry sh -c "git submodule deinit -f $module && \
|
||||
git submodule update --init --reference $cache_src_dir/$module $module"
|
||||
git submodule update --init --recursive --reference $cache_src_dir/$module $module"
|
||||
done
|
||||
|
||||
travis_fold end update_submodules
|
||||
|
@ -1 +0,0 @@
|
||||
Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35
|
@ -1,35 +0,0 @@
|
||||
# `compiler_builtins_lib`
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
This feature is required to link to the `compiler_builtins` crate which contains
|
||||
"compiler intrinsics". Compiler intrinsics are software implementations of basic
|
||||
operations like multiplication of `u64`s. These intrinsics are only required on
|
||||
platforms where these operations don't directly map to a hardware instruction.
|
||||
|
||||
You should never need to explicitly link to the `compiler_builtins` crate when
|
||||
building "std" programs as `compiler_builtins` is already in the dependency
|
||||
graph of `std`. But you may need it when building `no_std` **binary** crates. If
|
||||
you get a *linker* error like:
|
||||
|
||||
``` text
|
||||
$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul'
|
||||
$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod'
|
||||
```
|
||||
|
||||
That means that you need to link to this crate.
|
||||
|
||||
When you link to this crate, make sure it only appears once in your crate
|
||||
dependency graph. Also, it doesn't matter where in the dependency graph, you
|
||||
place the `compiler_builtins` crate.
|
||||
|
||||
<!-- NOTE(ignore) doctests don't support `no_std` binaries -->
|
||||
|
||||
``` rust,ignore
|
||||
#![feature(compiler_builtins_lib)]
|
||||
#![no_std]
|
||||
|
||||
extern crate compiler_builtins;
|
||||
```
|
1
src/libcompiler_builtins
Submodule
1
src/libcompiler_builtins
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 238647af806470dc73e585c03682083931d29cd5
|
@ -1,19 +0,0 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
name = "compiler_builtins"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "compiler_builtins"
|
||||
path = "lib.rs"
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../libcore" }
|
||||
|
||||
[build-dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
gcc = "0.3.50"
|
@ -1,423 +0,0 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
//!
|
||||
//! Note that while compiler-rt has a build system associated with it, we
|
||||
//! specifically don't use it here. The compiler-rt build system, written in
|
||||
//! CMake, is actually *very* difficult to work with in terms of getting it to
|
||||
//! compile on all the relevant platforms we want it to compile on. In the end
|
||||
//! it became so much pain to work with local patches, work around the oddities
|
||||
//! of the build system, etc, that we're just building everything by hand now.
|
||||
//!
|
||||
//! In general compiler-rt is just a bunch of intrinsics that are in practice
|
||||
//! *very* stable. We just need to make sure that all the relevant functions and
|
||||
//! such are compiled somewhere and placed in an object file somewhere.
|
||||
//! Eventually, these should all be written in Rust!
|
||||
//!
|
||||
//! So below you'll find a listing of every single file in the compiler-rt repo
|
||||
//! that we're compiling. We just reach in and compile with the `gcc` crate
|
||||
//! which should have all the relevant flags and such already configured.
|
||||
//!
|
||||
//! The risk here is that if we update compiler-rt we may need to compile some
|
||||
//! new intrinsics, but to be honest we surely don't use all of the intrinsics
|
||||
//! listed below today so the likelihood of us actually needing a new intrinsic
|
||||
//! is quite low. The failure case is also just that someone reports a link
|
||||
//! error (if any) and then we just add it to the list. Overall, that cost is
|
||||
//! far far less than working with compiler-rt's build system over time.
|
||||
|
||||
extern crate build_helper;
|
||||
extern crate gcc;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use build_helper::native_lib_boilerplate;
|
||||
|
||||
struct Sources {
|
||||
// SYMBOL -> PATH TO SOURCE
|
||||
map: BTreeMap<&'static str, &'static str>,
|
||||
}
|
||||
|
||||
impl Sources {
|
||||
fn new() -> Sources {
|
||||
Sources { map: BTreeMap::new() }
|
||||
}
|
||||
|
||||
fn extend(&mut self, sources: &[&'static str]) {
|
||||
// NOTE Some intrinsics have both a generic implementation (e.g.
|
||||
// `floatdidf.c`) and an arch optimized implementation
|
||||
// (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized
|
||||
// implementation and discard the generic implementation. If we don't
|
||||
// and keep both implementations, the linker will yell at us about
|
||||
// duplicate symbols!
|
||||
for &src in sources {
|
||||
let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap();
|
||||
if src.contains("/") {
|
||||
// Arch-optimized implementation (preferred)
|
||||
self.map.insert(symbol, src);
|
||||
} else {
|
||||
// Generic implementation
|
||||
if !self.map.contains_key(symbol) {
|
||||
self.map.insert(symbol, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").expect("TARGET was not set");
|
||||
|
||||
// Emscripten's runtime includes all the builtins
|
||||
if target.contains("emscripten") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't reuse `sources` list for the freshness check becuse it doesn't contain header files.
|
||||
let native = match native_lib_boilerplate("compiler-rt", "compiler-rt", "compiler-rt", ".") {
|
||||
Ok(native) => native,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let cfg = &mut gcc::Config::new();
|
||||
cfg.out_dir(&native.out_dir);
|
||||
|
||||
if target.contains("msvc") {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
// Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
|
||||
cfg.define("__func__", Some("__FUNCTION__"));
|
||||
} else {
|
||||
// Turn off various features of gcc and such, mostly copying
|
||||
// compiler-rt's build system already
|
||||
cfg.flag("-fno-builtin");
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
// Accepted practice on Solaris is to never omit frame pointer so that
|
||||
// system observability tools work as expected. In addition, at least
|
||||
// on Solaris, -fomit-frame-pointer on sparcv9 appears to generate
|
||||
// references to data outside of the current stack frame. A search of
|
||||
// the gcc bug database provides a variety of issues surrounding
|
||||
// -fomit-frame-pointer on non-x86 platforms.
|
||||
if !target.contains("solaris") && !target.contains("sparc") {
|
||||
cfg.flag("-fomit-frame-pointer");
|
||||
}
|
||||
cfg.flag("-ffreestanding");
|
||||
cfg.define("VISIBILITY_HIDDEN", None);
|
||||
}
|
||||
|
||||
let mut sources = Sources::new();
|
||||
sources.extend(&["absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"apple_versioning.c",
|
||||
"ashldi3.c",
|
||||
"ashrdi3.c",
|
||||
"clzdi2.c",
|
||||
"clzsi2.c",
|
||||
"cmpdi2.c",
|
||||
"comparedf2.c",
|
||||
"comparesf2.c",
|
||||
"ctzdi2.c",
|
||||
"ctzsi2.c",
|
||||
"divdc3.c",
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
"divmodsi4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divxc3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
"fixdfdi.c",
|
||||
"fixdfsi.c",
|
||||
"fixsfdi.c",
|
||||
"fixsfsi.c",
|
||||
"fixunsdfdi.c",
|
||||
"fixunsdfsi.c",
|
||||
"fixunssfdi.c",
|
||||
"fixunssfsi.c",
|
||||
"fixunsxfdi.c",
|
||||
"fixunsxfsi.c",
|
||||
"fixxfdi.c",
|
||||
"floatdidf.c",
|
||||
"floatdisf.c",
|
||||
"floatdixf.c",
|
||||
"floatsidf.c",
|
||||
"floatsisf.c",
|
||||
"floatundidf.c",
|
||||
"floatundisf.c",
|
||||
"floatundixf.c",
|
||||
"floatunsidf.c",
|
||||
"floatunsisf.c",
|
||||
"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"moddi3.c",
|
||||
"modsi3.c",
|
||||
"muldc3.c",
|
||||
"muldf3.c",
|
||||
"muldi3.c",
|
||||
"mulodi4.c",
|
||||
"mulosi4.c",
|
||||
"muloti4.c",
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulxc3.c",
|
||||
"negdf2.c",
|
||||
"negdi2.c",
|
||||
"negsf2.c",
|
||||
"negvdi2.c",
|
||||
"negvsi2.c",
|
||||
"paritydi2.c",
|
||||
"paritysi2.c",
|
||||
"popcountdi2.c",
|
||||
"popcountsi2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powixf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
"truncsfhf2.c",
|
||||
"ucmpdi2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
"udivmodsi4.c",
|
||||
"udivsi3.c",
|
||||
"umoddi3.c",
|
||||
"umodsi3.c"]);
|
||||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(&["absvti2.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
"fixsfti.c",
|
||||
"fixunsdfti.c",
|
||||
"fixunssfti.c",
|
||||
"fixunsxfti.c",
|
||||
"fixxfti.c",
|
||||
"floattidf.c",
|
||||
"floattisf.c",
|
||||
"floattixf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"subvti3.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
"umodti3.c"]);
|
||||
}
|
||||
|
||||
if target.contains("apple") {
|
||||
sources.extend(&["atomic_flag_clear.c",
|
||||
"atomic_flag_clear_explicit.c",
|
||||
"atomic_flag_test_and_set.c",
|
||||
"atomic_flag_test_and_set_explicit.c",
|
||||
"atomic_signal_fence.c",
|
||||
"atomic_thread_fence.c"]);
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") && !target.contains("netbsd") {
|
||||
sources.extend(&["gcc_personality_v0.c"]);
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/chkstk.S",
|
||||
"x86_64/chkstk2.S",
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
"x86_64/floatundidf.S",
|
||||
"x86_64/floatundisf.S",
|
||||
"x86_64/floatundixf.S"]);
|
||||
}
|
||||
|
||||
if target.contains("i386") || target.contains("i586") || target.contains("i686") {
|
||||
sources.extend(&["i386/ashldi3.S",
|
||||
"i386/ashrdi3.S",
|
||||
"i386/chkstk.S",
|
||||
"i386/chkstk2.S",
|
||||
"i386/divdi3.S",
|
||||
"i386/floatdidf.S",
|
||||
"i386/floatdisf.S",
|
||||
"i386/floatdixf.S",
|
||||
"i386/floatundidf.S",
|
||||
"i386/floatundisf.S",
|
||||
"i386/floatundixf.S",
|
||||
"i386/lshrdi3.S",
|
||||
"i386/moddi3.S",
|
||||
"i386/muldi3.S",
|
||||
"i386/udivdi3.S",
|
||||
"i386/umoddi3.S"]);
|
||||
}
|
||||
}
|
||||
|
||||
if target.contains("arm") && !target.contains("ios") {
|
||||
// (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by
|
||||
// default, we don't want Thumb 2 since it isn't supported on some
|
||||
// devices, so disable thumb entirely.
|
||||
// Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492
|
||||
cfg.define("__ARM_ARCH_ISA_THUMB", Some("0"));
|
||||
|
||||
sources.extend(&["arm/aeabi_cdcmp.S",
|
||||
"arm/aeabi_cdcmpeq_check_nan.c",
|
||||
"arm/aeabi_cfcmp.S",
|
||||
"arm/aeabi_cfcmpeq_check_nan.c",
|
||||
"arm/aeabi_dcmp.S",
|
||||
"arm/aeabi_div0.c",
|
||||
"arm/aeabi_drsub.c",
|
||||
"arm/aeabi_fcmp.S",
|
||||
"arm/aeabi_frsub.c",
|
||||
"arm/aeabi_idivmod.S",
|
||||
"arm/aeabi_ldivmod.S",
|
||||
"arm/aeabi_memcmp.S",
|
||||
"arm/aeabi_memcpy.S",
|
||||
"arm/aeabi_memmove.S",
|
||||
"arm/aeabi_memset.S",
|
||||
"arm/aeabi_uidivmod.S",
|
||||
"arm/aeabi_uldivmod.S",
|
||||
"arm/bswapdi2.S",
|
||||
"arm/bswapsi2.S",
|
||||
"arm/clzdi2.S",
|
||||
"arm/clzsi2.S",
|
||||
"arm/comparesf2.S",
|
||||
"arm/divmodsi4.S",
|
||||
"arm/divsi3.S",
|
||||
"arm/modsi3.S",
|
||||
"arm/switch16.S",
|
||||
"arm/switch32.S",
|
||||
"arm/switch8.S",
|
||||
"arm/switchu8.S",
|
||||
"arm/sync_synchronize.S",
|
||||
"arm/udivmodsi4.S",
|
||||
"arm/udivsi3.S",
|
||||
"arm/umodsi3.S"]);
|
||||
}
|
||||
|
||||
if target.contains("armv7") {
|
||||
sources.extend(&["arm/sync_fetch_and_add_4.S",
|
||||
"arm/sync_fetch_and_add_8.S",
|
||||
"arm/sync_fetch_and_and_4.S",
|
||||
"arm/sync_fetch_and_and_8.S",
|
||||
"arm/sync_fetch_and_max_4.S",
|
||||
"arm/sync_fetch_and_max_8.S",
|
||||
"arm/sync_fetch_and_min_4.S",
|
||||
"arm/sync_fetch_and_min_8.S",
|
||||
"arm/sync_fetch_and_nand_4.S",
|
||||
"arm/sync_fetch_and_nand_8.S",
|
||||
"arm/sync_fetch_and_or_4.S",
|
||||
"arm/sync_fetch_and_or_8.S",
|
||||
"arm/sync_fetch_and_sub_4.S",
|
||||
"arm/sync_fetch_and_sub_8.S",
|
||||
"arm/sync_fetch_and_umax_4.S",
|
||||
"arm/sync_fetch_and_umax_8.S",
|
||||
"arm/sync_fetch_and_umin_4.S",
|
||||
"arm/sync_fetch_and_umin_8.S",
|
||||
"arm/sync_fetch_and_xor_4.S",
|
||||
"arm/sync_fetch_and_xor_8.S"]);
|
||||
}
|
||||
|
||||
if target.contains("eabihf") {
|
||||
sources.extend(&["arm/adddf3vfp.S",
|
||||
"arm/addsf3vfp.S",
|
||||
"arm/divdf3vfp.S",
|
||||
"arm/divsf3vfp.S",
|
||||
"arm/eqdf2vfp.S",
|
||||
"arm/eqsf2vfp.S",
|
||||
"arm/extendsfdf2vfp.S",
|
||||
"arm/fixdfsivfp.S",
|
||||
"arm/fixsfsivfp.S",
|
||||
"arm/fixunsdfsivfp.S",
|
||||
"arm/fixunssfsivfp.S",
|
||||
"arm/floatsidfvfp.S",
|
||||
"arm/floatsisfvfp.S",
|
||||
"arm/floatunssidfvfp.S",
|
||||
"arm/floatunssisfvfp.S",
|
||||
"arm/gedf2vfp.S",
|
||||
"arm/gesf2vfp.S",
|
||||
"arm/gtdf2vfp.S",
|
||||
"arm/gtsf2vfp.S",
|
||||
"arm/ledf2vfp.S",
|
||||
"arm/lesf2vfp.S",
|
||||
"arm/ltdf2vfp.S",
|
||||
"arm/ltsf2vfp.S",
|
||||
"arm/muldf3vfp.S",
|
||||
"arm/mulsf3vfp.S",
|
||||
"arm/negdf2vfp.S",
|
||||
"arm/negsf2vfp.S",
|
||||
"arm/nedf2vfp.S",
|
||||
"arm/nesf2vfp.S",
|
||||
"arm/restore_vfp_d8_d15_regs.S",
|
||||
"arm/save_vfp_d8_d15_regs.S",
|
||||
"arm/subdf3vfp.S",
|
||||
"arm/subsf3vfp.S",
|
||||
"arm/truncdfsf2vfp.S",
|
||||
"arm/unorddf2vfp.S",
|
||||
"arm/unordsf2vfp.S"]);
|
||||
}
|
||||
|
||||
if target.contains("aarch64") {
|
||||
sources.extend(&["comparetf2.c",
|
||||
"extenddftf2.c",
|
||||
"extendsftf2.c",
|
||||
"fixtfdi.c",
|
||||
"fixtfsi.c",
|
||||
"fixtfti.c",
|
||||
"fixunstfdi.c",
|
||||
"fixunstfsi.c",
|
||||
"fixunstfti.c",
|
||||
"floatditf.c",
|
||||
"floatsitf.c",
|
||||
"floatunditf.c",
|
||||
"floatunsitf.c",
|
||||
"multc3.c",
|
||||
"trunctfdf2.c",
|
||||
"trunctfsf2.c"]);
|
||||
}
|
||||
|
||||
for src in sources.map.values() {
|
||||
cfg.file(Path::new("../compiler-rt/lib/builtins").join(src));
|
||||
}
|
||||
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
@ -1,721 +0,0 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(compiler_builtins)]
|
||||
#![no_std]
|
||||
#![compiler_builtins]
|
||||
#![unstable(feature = "compiler_builtins_lib",
|
||||
reason = "internal implementation detail of rustc right now",
|
||||
issue = "0")]
|
||||
#![crate_name = "compiler_builtins"]
|
||||
#![crate_type = "rlib"]
|
||||
#![allow(unused_features)]
|
||||
#![feature(staged_api, core_intrinsics, repr_simd,
|
||||
i128_type, core_float, abi_unadjusted, associated_consts)]
|
||||
#![allow(non_camel_case_types, unused_variables, unused_imports)]
|
||||
|
||||
#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows",
|
||||
target_arch="mips64"))]
|
||||
pub mod reimpls {
|
||||
|
||||
#![allow(unused_comparisons)]
|
||||
|
||||
use core::intrinsics::unchecked_div;
|
||||
use core::intrinsics::unchecked_rem;
|
||||
use core::ptr;
|
||||
|
||||
macro_rules! ashl {
|
||||
($a:expr, $b:expr, $ty:ty) => {{
|
||||
let (a, b) = ($a, $b);
|
||||
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
|
||||
let half_bits = bits.wrapping_shr(1);
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts(0, a.low().wrapping_shl(
|
||||
b.wrapping_sub(half_bits) as u32))
|
||||
} else if b == 0 {
|
||||
a
|
||||
} else {
|
||||
<$ty>::from_parts(a.low().wrapping_shl(b as u32),
|
||||
a.high().wrapping_shl(b as u32)
|
||||
| a.low()
|
||||
.wrapping_shr(half_bits.wrapping_sub(b) as u32))
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[export_name="__ashlti3"]
|
||||
pub extern "C" fn shl(a: u128, b: u128) -> u128 {
|
||||
ashl!(a, b, u128)
|
||||
}
|
||||
|
||||
macro_rules! ashr {
|
||||
($a: expr, $b: expr, $ty:ty) => {{
|
||||
let (a, b) = ($a, $b);
|
||||
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
|
||||
let half_bits = bits.wrapping_shr(1);
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32)
|
||||
as <$ty as LargeInt>::LowHalf,
|
||||
a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32))
|
||||
} else if b == 0 {
|
||||
a
|
||||
} else {
|
||||
let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf;
|
||||
<$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32)
|
||||
| a.low().wrapping_shr(b as u32),
|
||||
a.high().wrapping_shr(b as u32))
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[export_name="__ashrti3"]
|
||||
pub extern "C" fn shr(a: i128, b: i128) -> i128 {
|
||||
ashr!(a, b, i128)
|
||||
}
|
||||
|
||||
macro_rules! lshr {
|
||||
($a: expr, $b: expr, $ty:ty) => {{
|
||||
let (a, b) = ($a, $b);
|
||||
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
|
||||
let half_bits = bits.wrapping_shr(1);
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0)
|
||||
} else if b == 0 {
|
||||
a
|
||||
} else {
|
||||
<$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32)
|
||||
| a.low().wrapping_shr(b as u32),
|
||||
a.high().wrapping_shr(b as u32))
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
#[export_name="__lshrti3"]
|
||||
pub extern "C" fn lshr(a: u128, b: u128) -> u128 {
|
||||
lshr!(a, b, u128)
|
||||
}
|
||||
|
||||
pub extern "C" fn u128_div_mod(n: u128, d: u128, rem: *mut u128) -> u128 {
|
||||
// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
|
||||
unsafe {
|
||||
// special cases, X is unknown, K != 0
|
||||
if n.high() == 0 {
|
||||
if d.high() == 0 {
|
||||
// 0 X
|
||||
// ---
|
||||
// 0 X
|
||||
if !rem.is_null() {
|
||||
*rem = u128::from(unchecked_rem(n.low(), d.low()));
|
||||
}
|
||||
return u128::from(unchecked_div(n.low(), d.low()));
|
||||
} else {
|
||||
// 0 X
|
||||
// ---
|
||||
// K X
|
||||
if !rem.is_null() {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
let mut sr;
|
||||
let mut q;
|
||||
let mut r;
|
||||
|
||||
if d.low() == 0 {
|
||||
if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 0
|
||||
if !rem.is_null() {
|
||||
*rem = u128::from(unchecked_rem(n.high(), d.low()));
|
||||
}
|
||||
return u128::from(unchecked_div(n.high(), d.low()));
|
||||
}
|
||||
|
||||
if n.low() == 0 {
|
||||
// K 0
|
||||
// ---
|
||||
// K 0
|
||||
if !rem.is_null() {
|
||||
*rem = u128::from_parts(0, unchecked_rem(n.high(), d.high()));
|
||||
}
|
||||
return u128::from(unchecked_div(n.high(), d.high()));
|
||||
}
|
||||
|
||||
// K K
|
||||
// ---
|
||||
// K 0
|
||||
|
||||
if d.high().is_power_of_two() {
|
||||
if !rem.is_null() {
|
||||
*rem = u128::from_parts(n.low(),
|
||||
n.high() & (d.high().wrapping_sub(1)));
|
||||
}
|
||||
return u128::from(n.high().wrapping_shr(d.high().trailing_zeros()));
|
||||
}
|
||||
|
||||
// K K
|
||||
// ---
|
||||
// K 0
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > 64 - 2 {
|
||||
if !rem.is_null() {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr = sr.wrapping_add(1);
|
||||
|
||||
// 1 <= sr <= u64::bits() - 1
|
||||
q = n.wrapping_shl(128u32.wrapping_sub(sr));
|
||||
r = n.wrapping_shr(sr);
|
||||
} else {
|
||||
if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 K
|
||||
if d.low().is_power_of_two() {
|
||||
if !rem.is_null() {
|
||||
*rem = u128::from(n.low() & (d.low().wrapping_sub(1)));
|
||||
}
|
||||
|
||||
if d.low() == 1 {
|
||||
return n;
|
||||
} else {
|
||||
let sr = d.low().trailing_zeros();
|
||||
return n.wrapping_shr(sr);
|
||||
};
|
||||
}
|
||||
|
||||
sr = (1 + 64u32)
|
||||
.wrapping_add(d.low().leading_zeros())
|
||||
.wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// 2 <= sr <= u64::bits() - 1
|
||||
q = n.wrapping_shl(128u32.wrapping_sub(sr));
|
||||
r = n.wrapping_shr(sr);
|
||||
// FIXME the C compiler-rt implementation has something here
|
||||
// that looks like a speed optimisation.
|
||||
// It would be worth a try to port it to Rust too and
|
||||
// compare the speed.
|
||||
} else {
|
||||
// K X
|
||||
// ---
|
||||
// K K
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > 64 - 1 {
|
||||
if !rem.is_null() {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr = sr.wrapping_add(1);
|
||||
|
||||
// 1 <= sr <= u32::bits()
|
||||
q = n.wrapping_shl(128u32.wrapping_sub(sr));
|
||||
r = n.wrapping_shr(sr);
|
||||
}
|
||||
}
|
||||
|
||||
// Not a special case
|
||||
// q and r are initialized with
|
||||
// q = n << (u64::bits() - sr)
|
||||
// r = n >> sr
|
||||
// 1 <= sr <= u64::bits() - 1
|
||||
let mut carry = 0;
|
||||
|
||||
// FIXME: replace this with a for loop
|
||||
// (atm not doable as this generates call to
|
||||
// eh_personality when optimisations are turned off,
|
||||
// which in turn gives a linker error in later
|
||||
// compilation steps)
|
||||
while sr > 0 {
|
||||
// r:q = ((r:q) << 1) | carry
|
||||
r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1);
|
||||
q = q.wrapping_shl(1) | carry as u128;
|
||||
|
||||
// carry = 0
|
||||
// if r >= d {
|
||||
// r -= d;
|
||||
// carry = 1;
|
||||
// }
|
||||
let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1);
|
||||
carry = (s & 1) as u64;
|
||||
r = r.wrapping_sub(d & s as u128);
|
||||
sr = sr.wrapping_sub(1);
|
||||
}
|
||||
|
||||
if !rem.is_null() {
|
||||
*rem = r;
|
||||
}
|
||||
(q.wrapping_shl(1)) | carry as u128
|
||||
}
|
||||
}
|
||||
|
||||
fn i128_mod(a: i128, b: i128) -> i128 {
|
||||
let b = b.uabs();
|
||||
let sa = a.signum();
|
||||
let a = a.uabs();
|
||||
unsafe {
|
||||
let mut r = ::core::mem::zeroed();
|
||||
u128_div_mod(a, b, &mut r);
|
||||
if sa == -1 { (r as i128).unchecked_neg() } else { r as i128 }
|
||||
}
|
||||
}
|
||||
|
||||
fn i128_div(a: i128, b: i128) -> i128 {
|
||||
let sa = a.signum();
|
||||
let sb = b.signum();
|
||||
let a = a.uabs();
|
||||
let b = b.uabs();
|
||||
let sr = sa.wrapping_mul(sb); // sign of quotient
|
||||
(if sr == -1 {
|
||||
(u128_div_mod(a, b, ptr::null_mut()) as i128).unchecked_neg()
|
||||
} else {
|
||||
u128_div_mod(a, b, ptr::null_mut()) as i128
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! mulo {
|
||||
($a:expr, $b:expr, $o: expr, $ty: ty) => {{
|
||||
let (a, b, overflow) = ($a, $b, $o);
|
||||
*overflow = 0;
|
||||
let result = a.wrapping_mul(b);
|
||||
if a == <$ty>::min_value() {
|
||||
if b != 0 && b != 1 {
|
||||
*overflow = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if b == <$ty>::min_value() {
|
||||
if a != 0 && a != 1 {
|
||||
*overflow = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let sa = a.signum();
|
||||
let abs_a = a.iabs();
|
||||
let sb = b.signum();
|
||||
let abs_b = b.iabs();
|
||||
if abs_a < 2 || abs_b < 2 {
|
||||
return result;
|
||||
}
|
||||
if sa == sb {
|
||||
if abs_a > unchecked_div(<$ty>::max_value(), abs_b) {
|
||||
*overflow = 1;
|
||||
}
|
||||
} else {
|
||||
if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) {
|
||||
*overflow = 1;
|
||||
}
|
||||
}
|
||||
result
|
||||
}}
|
||||
}
|
||||
|
||||
pub trait LargeInt {
|
||||
type LowHalf;
|
||||
type HighHalf;
|
||||
|
||||
fn low(self) -> Self::LowHalf;
|
||||
fn high(self) -> Self::HighHalf;
|
||||
fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
|
||||
}
|
||||
impl LargeInt for u128 {
|
||||
type LowHalf = u64;
|
||||
type HighHalf = u64;
|
||||
|
||||
fn low(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn high(self) -> u64 {
|
||||
self.wrapping_shr(64) as u64
|
||||
}
|
||||
fn from_parts(low: u64, high: u64) -> u128 {
|
||||
(high as u128).wrapping_shl(64) | low as u128
|
||||
}
|
||||
}
|
||||
impl LargeInt for i128 {
|
||||
type LowHalf = u64;
|
||||
type HighHalf = i64;
|
||||
|
||||
fn low(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn high(self) -> i64 {
|
||||
self.wrapping_shr(64) as i64
|
||||
}
|
||||
fn from_parts(low: u64, high: i64) -> i128 {
|
||||
u128::from_parts(low, high as u64) as i128
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul {
|
||||
($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{
|
||||
let (a, b) = ($a, $b);
|
||||
let half_bits = ::core::mem::size_of::<$tyh>().wrapping_mul(4) as u32;
|
||||
let lower_mask = (!0u64).wrapping_shr(half_bits);
|
||||
let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
|
||||
let mut t = low.wrapping_shr(half_bits);
|
||||
low &= lower_mask;
|
||||
t = t.wrapping_add(a.low().wrapping_shr(half_bits)
|
||||
.wrapping_mul(b.low() & lower_mask));
|
||||
low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
|
||||
let mut high = t.wrapping_shr(half_bits) as $tyh;
|
||||
t = low.wrapping_shr(half_bits);
|
||||
low &= lower_mask;
|
||||
t = t.wrapping_add(b.low().wrapping_shr(half_bits)
|
||||
.wrapping_mul(a.low() & lower_mask));
|
||||
low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
|
||||
high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh);
|
||||
high = high.wrapping_add(a.low().wrapping_shr(half_bits)
|
||||
.wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh);
|
||||
high = high
|
||||
.wrapping_add(a.high()
|
||||
.wrapping_mul(b.low() as $tyh))
|
||||
.wrapping_add((a.low() as $tyh)
|
||||
.wrapping_mul(b.high()));
|
||||
<$ty>::from_parts(low, high)
|
||||
}}
|
||||
}
|
||||
|
||||
#[export_name="__multi3"]
|
||||
pub extern "C" fn u128_mul(a: i128, b: i128) -> i128 {
|
||||
mul!(a, b, i128, i64)
|
||||
}
|
||||
|
||||
trait AbsExt: Sized {
|
||||
fn uabs(self) -> u128;
|
||||
fn iabs(self) -> i128;
|
||||
}
|
||||
|
||||
impl AbsExt for i128 {
|
||||
fn uabs(self) -> u128 {
|
||||
self.iabs() as u128
|
||||
}
|
||||
fn iabs(self) -> i128 {
|
||||
let s = self.wrapping_shr(127);
|
||||
((self ^ s).wrapping_sub(s))
|
||||
}
|
||||
}
|
||||
|
||||
trait NegExt: Sized {
|
||||
fn unchecked_neg(self) -> i128;
|
||||
}
|
||||
|
||||
impl NegExt for i128 {
|
||||
fn unchecked_neg(self) -> i128 {
|
||||
(!self).wrapping_add(1)
|
||||
}
|
||||
}
|
||||
|
||||
trait FloatStuff: Sized {
|
||||
type ToBytes;
|
||||
|
||||
const MANTISSA_BITS: u32;
|
||||
const MAX_EXP: i32;
|
||||
const EXP_MASK: Self::ToBytes;
|
||||
const MANTISSA_MASK: Self::ToBytes;
|
||||
const MANTISSA_LEAD_BIT: Self::ToBytes;
|
||||
|
||||
fn to_bytes(self) -> Self::ToBytes;
|
||||
fn get_exponent(self) -> i32;
|
||||
}
|
||||
|
||||
impl FloatStuff for f32 {
|
||||
type ToBytes = u32;
|
||||
const MANTISSA_BITS: u32 = 23;
|
||||
const MAX_EXP: i32 = 127;
|
||||
const EXP_MASK: u32 = 0x7F80_0000;
|
||||
const MANTISSA_MASK: u32 = 0x007F_FFFF;
|
||||
const MANTISSA_LEAD_BIT: u32 = 0x0080_0000;
|
||||
|
||||
fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } }
|
||||
fn get_exponent(self) -> i32 {
|
||||
((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
|
||||
.wrapping_sub(Self::MAX_EXP)
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatStuff for f64 {
|
||||
type ToBytes = u64;
|
||||
const MANTISSA_BITS: u32 = 52;
|
||||
const MAX_EXP: i32 = 1023;
|
||||
const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
|
||||
const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
|
||||
const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000;
|
||||
|
||||
fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } }
|
||||
fn get_exponent(self) -> i32 {
|
||||
((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
|
||||
.wrapping_sub(Self::MAX_EXP)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! float_as_unsigned {
|
||||
($from: expr, $fromty: ty, $outty: ty) => { {
|
||||
use core::num::Float;
|
||||
let repr = $from.to_bytes();
|
||||
let sign = $from.signum();
|
||||
let exponent = $from.get_exponent();
|
||||
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
||||
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
||||
if sign == -1.0 || exponent < 0 { return 0 as u128; }
|
||||
if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
|
||||
return !(0 as u128);
|
||||
}
|
||||
(if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
|
||||
.wrapping_sub(exponent) as u32)
|
||||
} else {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shl(exponent.wrapping_sub(
|
||||
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
||||
})
|
||||
} }
|
||||
}
|
||||
|
||||
macro_rules! float_as_signed {
|
||||
($from: expr, $fromty: ty, $outty: ty) => {{
|
||||
use core::num::Float;
|
||||
let repr = $from.to_bytes();
|
||||
let sign = $from.signum();
|
||||
let exponent = $from.get_exponent();
|
||||
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
||||
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
||||
|
||||
if exponent < 0 { return 0 as i128; }
|
||||
if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
|
||||
let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() };
|
||||
return ret
|
||||
}
|
||||
let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
|
||||
.wrapping_sub(exponent) as u32)
|
||||
} else {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shl(exponent.wrapping_sub(
|
||||
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
||||
};
|
||||
(if sign >= 0.0 { r } else { r.unchecked_neg() })
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
fn i128_as_f64(a: i128) -> f64 {
|
||||
match a.signum() {
|
||||
1 => u128_as_f64(a.uabs()),
|
||||
0 => 0.0,
|
||||
_ => -u128_as_f64(a.uabs()),
|
||||
}
|
||||
}
|
||||
|
||||
fn i128_as_f32(a: i128) -> f32 {
|
||||
match a.signum() {
|
||||
1 => u128_as_f32(a.uabs()),
|
||||
0 => 0.0,
|
||||
_ => -u128_as_f32(a.uabs()),
|
||||
}
|
||||
}
|
||||
|
||||
fn u128_as_f64(mut a: u128) -> f64 {
|
||||
use ::core::f64::MANTISSA_DIGITS;
|
||||
if a == 0 { return 0.0; }
|
||||
let sd = 128u32.wrapping_sub(a.leading_zeros());
|
||||
let mut e = sd.wrapping_sub(1);
|
||||
const MD1 : u32 = MANTISSA_DIGITS + 1;
|
||||
const MD2 : u32 = MANTISSA_DIGITS + 2;
|
||||
|
||||
let negn = !0u128;
|
||||
|
||||
if sd > MANTISSA_DIGITS {
|
||||
a = match sd {
|
||||
MD1 => a.wrapping_shl(1),
|
||||
MD2 => a,
|
||||
_ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
|
||||
(if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
|
||||
.wrapping_sub(sd as u128))) == 0 { 0 } else { 1 })
|
||||
};
|
||||
a |= if (a & 4) == 0 { 0 } else { 1 };
|
||||
a = a.wrapping_add(1);
|
||||
a = a.wrapping_shr(2);
|
||||
if a & (1 << MANTISSA_DIGITS) != 0 {
|
||||
a = a.wrapping_shr(1);
|
||||
e = e.wrapping_add(1);
|
||||
}
|
||||
} else {
|
||||
a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
|
||||
}
|
||||
unsafe {
|
||||
::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52)
|
||||
| (a as u64 & 0x000f_ffff_ffff_ffff))
|
||||
}
|
||||
}
|
||||
|
||||
fn u128_as_f32(mut a: u128) -> f32 {
|
||||
use ::core::f32::MANTISSA_DIGITS;
|
||||
if a == 0 { return 0.0; }
|
||||
let sd = 128u32.wrapping_sub(a.leading_zeros());
|
||||
let mut e = sd.wrapping_sub(1);
|
||||
const MD1 : u32 = MANTISSA_DIGITS + 1;
|
||||
const MD2 : u32 = MANTISSA_DIGITS + 2;
|
||||
|
||||
let negn = !0u128;
|
||||
|
||||
if sd > MANTISSA_DIGITS {
|
||||
a = match sd {
|
||||
MD1 => a.wrapping_shl(1),
|
||||
MD2 => a,
|
||||
_ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
|
||||
(if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
|
||||
.wrapping_sub(sd as u128))) == 0 { 0 } else { 1 })
|
||||
};
|
||||
a |= if (a & 4) == 0 { 0 } else { 1 };
|
||||
a = a.wrapping_add(1);
|
||||
a = a.wrapping_shr(2);
|
||||
if a & (1 << MANTISSA_DIGITS) != 0 {
|
||||
a = a.wrapping_shr(1);
|
||||
e = e.wrapping_add(1);
|
||||
}
|
||||
} else {
|
||||
a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
|
||||
}
|
||||
unsafe {
|
||||
::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23)
|
||||
| (a as u32 & 0x007f_ffff))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! why_are_abi_strings_checked_by_parser { ($cret:ty, $conv:expr, $unadj:tt) => {
|
||||
mod imp {
|
||||
use super::{LargeInt, FloatStuff, NegExt, AbsExt};
|
||||
use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32,
|
||||
i128_div, i128_mod, u128_div_mod, unchecked_div, ptr};
|
||||
// For x64
|
||||
// rdx:rcx, r9:r8, stack -> rdx:rax
|
||||
// aka.
|
||||
// define i128 @__muloti4(i128, i128, i32*)
|
||||
#[export_name="__muloti4"]
|
||||
pub unsafe extern $unadj fn i128_mul_oflow(a: i128, b: i128, o: *mut i32) -> i128 {
|
||||
mulo!(a, b, o, i128)
|
||||
}
|
||||
|
||||
// For x64
|
||||
// rdx:rax -> xmm0
|
||||
// aka.
|
||||
// define double @__muloti4(i128)
|
||||
#[export_name="__floattidf"]
|
||||
pub extern $unadj fn i128_as_f64_(a: i128) -> f64 {
|
||||
i128_as_f64(a)
|
||||
}
|
||||
#[export_name="__floattisf"]
|
||||
pub extern $unadj fn i128_as_f32_(a: i128) -> f32 {
|
||||
i128_as_f32(a)
|
||||
}
|
||||
#[export_name="__floatuntidf"]
|
||||
pub extern $unadj fn u128_as_f64_(a: u128) -> f64 {
|
||||
u128_as_f64(a)
|
||||
}
|
||||
#[export_name="__floatuntisf"]
|
||||
pub extern $unadj fn u128_as_f32_(a: u128) -> f32 {
|
||||
u128_as_f32(a)
|
||||
}
|
||||
|
||||
// For x64
|
||||
// xmm0 -> rdx:rax
|
||||
// aka.
|
||||
// define i128 @stuff(double)
|
||||
#[export_name="__fixunsdfti"]
|
||||
pub extern $unadj fn f64_as_u128(a: f64) -> u128 {
|
||||
float_as_unsigned!(a, f64, u128)
|
||||
}
|
||||
|
||||
#[export_name="__fixunssfti"]
|
||||
pub extern $unadj fn f32_as_u128(a: f32) -> u128 {
|
||||
float_as_unsigned!(a, f32, u128)
|
||||
}
|
||||
|
||||
#[export_name="__fixdfti"]
|
||||
pub extern $unadj fn f64_as_i128(a: f64) -> i128 {
|
||||
float_as_signed!(a, f64, i128)
|
||||
}
|
||||
|
||||
#[export_name="__fixsfti"]
|
||||
pub extern $unadj fn f32_as_i128(a: f32) -> i128 {
|
||||
float_as_signed!(a, f32, i128)
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
pub struct u64x2(u64, u64);
|
||||
|
||||
// For x64
|
||||
// pointers -> xmm0
|
||||
// aka.
|
||||
// define <2 x u64> @stuff(i128*, i128*, i128*)
|
||||
//
|
||||
// That almost matches the C ABI, so we simply use the C ABI
|
||||
#[export_name="__udivmodti4"]
|
||||
pub extern "C" fn u128_div_mod_(n: u128, d: u128, rem: *mut u128) -> $cret {
|
||||
let x = u128_div_mod(n, d, rem);
|
||||
($conv)(x)
|
||||
}
|
||||
|
||||
#[export_name="__udivti3"]
|
||||
pub extern "C" fn u128_div_(a: u128, b: u128) -> $cret {
|
||||
let x = u128_div_mod(a, b, ptr::null_mut());
|
||||
($conv)(x)
|
||||
}
|
||||
|
||||
#[export_name="__umodti3"]
|
||||
pub extern "C" fn u128_mod_(a: u128, b: u128) -> $cret {
|
||||
unsafe {
|
||||
let mut r = ::core::mem::zeroed();
|
||||
u128_div_mod(a, b, &mut r);
|
||||
($conv)(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name="__divti3"]
|
||||
pub extern "C" fn i128_div_(a: i128, b: i128) -> $cret {
|
||||
let x = i128_div(a, b);
|
||||
($conv)(x as u128)
|
||||
}
|
||||
|
||||
#[export_name="__modti3"]
|
||||
pub extern "C" fn i128_mod_(a: i128, b: i128) -> $cret {
|
||||
let x = i128_mod(a, b);
|
||||
($conv)(x as u128)
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
// LLVM expectations for ABI on windows x64 are pure madness.
|
||||
#[cfg(all(windows, target_pointer_width="64"))]
|
||||
why_are_abi_strings_checked_by_parser!(u64x2,
|
||||
|i: u128| u64x2(i.low(), i.high()),
|
||||
"unadjusted");
|
||||
|
||||
#[cfg(not(all(windows, target_pointer_width="64")))]
|
||||
why_are_abi_strings_checked_by_parser!(u128, |i|{ i }, "C");
|
||||
pub use self::imp::*;
|
||||
}
|
@ -53,7 +53,7 @@ fn main() {
|
||||
}
|
||||
|
||||
for src in profile_sources {
|
||||
cfg.file(Path::new("../compiler-rt/lib/profile").join(src));
|
||||
cfg.file(Path::new("../libcompiler_builtins/compiler-rt/lib/profile").join(src));
|
||||
}
|
||||
|
||||
cfg.compile("libprofiler-rt.a");
|
||||
|
@ -13,7 +13,7 @@ use std::ffi::{CStr, CString};
|
||||
|
||||
use llvm::{self, Attribute, ValueRef};
|
||||
use llvm::AttributePlace::Function;
|
||||
pub use syntax::attr::InlineAttr;
|
||||
pub use syntax::attr::{self, InlineAttr};
|
||||
use syntax::ast;
|
||||
use context::CrateContext;
|
||||
|
||||
|
@ -363,6 +363,24 @@ pub fn each_linked_rlib(sess: &Session,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a boolean indicating whether the specified crate should be ignored
|
||||
/// during LTO.
|
||||
///
|
||||
/// Crates ignored during LTO are not lumped together in the "massive object
|
||||
/// file" that we create and are linked in their normal rlib states. See
|
||||
/// comments below for what crates do not participate in LTO.
|
||||
///
|
||||
/// It's unusual for a crate to not participate in LTO. Typically only
|
||||
/// compiler-specific and unstable crates have a reason to not participate in
|
||||
/// LTO.
|
||||
pub fn ignored_for_lto(sess: &Session, cnum: CrateNum) -> bool {
|
||||
// `#![no_builtins]` crates don't participate in LTO because the state
|
||||
// of builtins gets messed up (our crate isn't tagged with no builtins).
|
||||
// Similarly `#![compiler_builtins]` doesn't participate because we want
|
||||
// those builtins!
|
||||
sess.cstore.is_no_builtins(cnum) || sess.cstore.is_compiler_builtins(cnum)
|
||||
}
|
||||
|
||||
fn out_filename(sess: &Session,
|
||||
crate_type: config::CrateType,
|
||||
outputs: &OutputFilenames,
|
||||
@ -698,7 +716,10 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
|
||||
let skip_object_files = native_libs.iter().any(|lib| {
|
||||
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
|
||||
});
|
||||
ab.add_rlib(path, &name.as_str(), sess.lto(), skip_object_files).unwrap();
|
||||
ab.add_rlib(path,
|
||||
&name.as_str(),
|
||||
sess.lto() && !ignored_for_lto(sess, cnum),
|
||||
skip_object_files).unwrap();
|
||||
|
||||
all_native_libs.extend(sess.cstore.native_libraries(cnum));
|
||||
});
|
||||
@ -1247,7 +1268,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
|
||||
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
|
||||
});
|
||||
|
||||
if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native {
|
||||
if (!sess.lto() || ignored_for_lto(sess, cnum)) &&
|
||||
crate_type != config::CrateTypeDylib &&
|
||||
!skip_native {
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
|
||||
return
|
||||
}
|
||||
|
@ -1200,8 +1200,7 @@ fn spawn_work<'a>(sess: &'a Session,
|
||||
let crate_types = sess.crate_types.borrow().clone();
|
||||
let mut each_linked_rlib_for_lto = Vec::new();
|
||||
drop(link::each_linked_rlib(sess, &mut |cnum, path| {
|
||||
// `#![no_builtins]` crates don't participate in LTO.
|
||||
if sess.cstore.is_no_builtins(cnum) {
|
||||
if link::ignored_for_lto(sess, cnum) {
|
||||
return
|
||||
}
|
||||
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
||||
|
@ -30,7 +30,6 @@ use context::CrateContext;
|
||||
use common;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
use syntax::attr;
|
||||
|
||||
use std::ffi::CString;
|
||||
|
||||
@ -88,16 +87,6 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
|
||||
}
|
||||
}
|
||||
|
||||
// If we're compiling the compiler-builtins crate, e.g. the equivalent of
|
||||
// compiler-rt, then we want to implicitly compile everything with hidden
|
||||
// visibility as we're going to link this object all over the place but
|
||||
// don't want the symbols to get exported.
|
||||
if attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
|
||||
unsafe {
|
||||
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) {
|
||||
Some("s") => {
|
||||
llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn);
|
||||
|
@ -162,6 +162,18 @@ impl<'a, 'tcx> TransItem<'tcx> {
|
||||
llvm::SetUniqueComdat(ccx.llmod(), lldecl);
|
||||
}
|
||||
|
||||
// If we're compiling the compiler-builtins crate, e.g. the equivalent of
|
||||
// compiler-rt, then we want to implicitly compile everything with hidden
|
||||
// visibility as we're going to link this object all over the place but
|
||||
// don't want the symbols to get exported.
|
||||
if linkage != llvm::Linkage::InternalLinkage &&
|
||||
linkage != llvm::Linkage::PrivateLinkage &&
|
||||
attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
|
||||
unsafe {
|
||||
llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
|
||||
if common::is_inline_instance(ccx.tcx(), &instance) {
|
||||
attributes::inline(lldecl, attributes::InlineAttr::Hint);
|
||||
|
@ -19,7 +19,7 @@ collections = { path = "../libcollections" }
|
||||
core = { path = "../libcore" }
|
||||
libc = { path = "../rustc/libc_shim" }
|
||||
rand = { path = "../librand" }
|
||||
compiler_builtins = { path = "../libcompiler_builtins" }
|
||||
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
|
||||
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
|
||||
std_unicode = { path = "../libstd_unicode" }
|
||||
unwind = { path = "../libunwind" }
|
||||
|
24
src/rustc/compiler_builtins_shim/Cargo.toml
Normal file
24
src/rustc/compiler_builtins_shim/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
# See libc_shim/Cargo.toml for why this exists
|
||||
|
||||
[package]
|
||||
name = "compiler_builtins"
|
||||
authors = ["The Rust Project Developers"]
|
||||
version = "0.0.0"
|
||||
build = "../../libcompiler_builtins/build.rs"
|
||||
|
||||
[lib]
|
||||
path = "../../libcompiler_builtins/src/lib.rs"
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../../libcore" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
|
||||
[features]
|
||||
c = []
|
||||
default = ["c", "rustbuild", "compiler-builtins"]
|
||||
rustbuild = []
|
||||
compiler-builtins = []
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,8 +8,11 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
#![crate_type = "staticlib"]
|
||||
#![deny(warnings)]
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn foo(x:i32) -> i32 { x }
|
||||
// See comments in Cargo.toml for why this exists
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rustc-cfg=stdbuild");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
@ -8,16 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:clibrary.rs
|
||||
// compile-flags: -lclibrary
|
||||
// compile-flags: -lrust_test_helpers
|
||||
|
||||
#[link(name = "clibrary", kind = "static")]
|
||||
#[link(name = "rust_test_helpers", kind = "static")]
|
||||
extern "C" {
|
||||
pub fn foo(x:i32) -> i32;
|
||||
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
foo(42);
|
||||
rust_dbg_extern_identity_u32(42);
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:clibrary.rs
|
||||
// compile-flags: -lstatic=wronglibrary:clibrary
|
||||
// compile-flags: -lstatic=wronglibrary:rust_test_helpers
|
||||
|
||||
#[link(name = "wronglibrary", kind = "dylib")]
|
||||
extern "C" {
|
||||
pub fn foo(x:i32) -> i32;
|
||||
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
foo(42);
|
||||
rust_dbg_extern_identity_u32(42);
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ fn filter_dirs(path: &Path) -> bool {
|
||||
"src/jemalloc",
|
||||
"src/llvm",
|
||||
"src/libbacktrace",
|
||||
"src/libcompiler_builtins",
|
||||
"src/compiler-rt",
|
||||
"src/rustllvm",
|
||||
"src/liblibc",
|
||||
|
Loading…
Reference in New Issue
Block a user