Merge pull request #76 from alexcrichton/more-test
Prep for and expand test infrastructure
This commit is contained in:
commit
52383edf3e
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"]
|
||||||
|
path = compiler-rt/compiler-rt-cdylib/compiler-rt
|
||||||
|
url = https://github.com/llvm-mirror/compiler-rt
|
65
.travis.yml
65
.travis.yml
|
@ -1,62 +1,63 @@
|
||||||
dist: trusty
|
dist: trusty
|
||||||
language: generic
|
language: rust
|
||||||
services: docker
|
services: docker
|
||||||
sudo: required
|
sudo: required
|
||||||
|
rust: nightly
|
||||||
|
cache: cargo
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- env: TARGET=aarch64-unknown-linux-gnu
|
- env: TARGET=aarch64-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
- env: TARGET=arm-unknown-linux-gnueabi
|
- env: TARGET=arm-unknown-linux-gnueabi
|
||||||
os: linux
|
# FIXME(rust-lang/rust#36518)
|
||||||
|
rust: nightly-2016-09-21
|
||||||
- env: TARGET=arm-unknown-linux-gnueabihf
|
- env: TARGET=arm-unknown-linux-gnueabihf
|
||||||
os: linux
|
|
||||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
- env: TARGET=armv7-unknown-linux-gnueabihf
|
||||||
os: linux
|
|
||||||
- env: TARGET=i586-unknown-linux-gnu
|
- env: TARGET=i586-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
- env: TARGET=i686-apple-darwin
|
- env: TARGET=i686-apple-darwin
|
||||||
language: ruby
|
# FIXME(rust-lang/rust#36793)
|
||||||
|
rust: nightly-2016-09-10
|
||||||
os: osx
|
os: osx
|
||||||
- env: TARGET=i686-unknown-linux-gnu
|
- env: TARGET=i686-unknown-linux-gnu
|
||||||
os: linux
|
# FIXME(rust-lang/rust#36793)
|
||||||
|
rust: nightly-2016-09-10
|
||||||
- env: TARGET=mips-unknown-linux-gnu
|
- env: TARGET=mips-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
- env: TARGET=mipsel-unknown-linux-gnu
|
- env: TARGET=mipsel-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
- env: TARGET=powerpc-unknown-linux-gnu
|
- env: TARGET=powerpc-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
- env: TARGET=powerpc64-unknown-linux-gnu
|
- env: TARGET=powerpc64-unknown-linux-gnu
|
||||||
os: linux
|
# QEMU crashes even when executing the simplest cross compiled C program:
|
||||||
- env: TARGET=powerpc64le-unknown-linux-gnu
|
# `int main() { return 0; }`
|
||||||
os: linux
|
- env: TARGET=powerpc64le-unknown-linux-gnu NO_RUN=1
|
||||||
- env: TARGET=thumbv6m-none-eabi
|
- env: TARGET=thumbv6m-none-eabi
|
||||||
os: linux
|
install: cargo install xargo --debug -f
|
||||||
- env: TARGET=thumbv6m-none-eabi WEAK=true
|
script: $HOME/.cargo/bin/xargo build --target $TARGET
|
||||||
os: linux
|
|
||||||
- env: TARGET=thumbv7em-none-eabi
|
- env: TARGET=thumbv7em-none-eabi
|
||||||
os: linux
|
install: cargo install xargo --debug -f
|
||||||
- env: TARGET=thumbv7em-none-eabi WEAK=true
|
script: $HOME/.cargo/bin/xargo build --target $TARGET
|
||||||
os: linux
|
|
||||||
- env: TARGET=thumbv7em-none-eabihf
|
- env: TARGET=thumbv7em-none-eabihf
|
||||||
os: linux
|
install: cargo install xargo --debug -f
|
||||||
- env: TARGET=thumbv7em-none-eabihf WEAK=true
|
script: $HOME/.cargo/bin/xargo build --target $TARGET
|
||||||
os: linux
|
|
||||||
- env: TARGET=thumbv7m-none-eabi
|
|
||||||
os: linux
|
|
||||||
- env: TARGET=thumbv7m-none-eabi WEAK=true
|
|
||||||
os: linux
|
|
||||||
- env: TARGET=x86_64-apple-darwin
|
- env: TARGET=x86_64-apple-darwin
|
||||||
language: ruby
|
|
||||||
os: osx
|
os: osx
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
os: linux
|
|
||||||
|
before_install:
|
||||||
|
- test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- bash ci/install.sh
|
- curl https://static.rust-lang.org/rustup.sh |
|
||||||
|
sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot`
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- bash ci/script.sh
|
- cargo generate-lockfile
|
||||||
|
- if [[ $TRAVIS_OS_NAME = "linux" ]]; then
|
||||||
|
sudo apt-get remove -y qemu-user-static &&
|
||||||
|
sudo apt-get install -y qemu-user-static &&
|
||||||
|
sh ci/run-docker.sh $TARGET;
|
||||||
|
else
|
||||||
|
cargo test --target $TARGET &&
|
||||||
|
cargo test --target $TARGET --release;
|
||||||
|
fi
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
|
|
@ -13,9 +13,8 @@ optional = true
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "0.3.1"
|
quickcheck = "0.3.1"
|
||||||
rand = "0.3.14"
|
rand = "0.3.14"
|
||||||
|
gcc_s = { path = "gcc_s" }
|
||||||
[dev-dependencies.gcc_s]
|
compiler-rt = { path = "compiler-rt" }
|
||||||
path = "gcc_s"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
weak = ["rlibc/weak"]
|
weak = ["rlibc/weak"]
|
||||||
|
|
|
@ -16,8 +16,8 @@ See [rust-lang/rust#35437][0].
|
||||||
|
|
||||||
If you are working with a target that doesn't have binary releases of std available via rustup (this
|
If you are working with a target that doesn't have binary releases of std available via rustup (this
|
||||||
probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you
|
probably means you are building the core crate yourself) and need compiler-rt intrinsics (i.e. you
|
||||||
are probably getting linker errors when building an executable: "undefined reference to
|
are probably getting linker errors when building an executable: `undefined reference to
|
||||||
__aeabi_memcpy"), you can use this crate to get those intrinsics and solve the linker errors. To do
|
__aeabi_memcpy`), you can use this crate to get those intrinsics and solve the linker errors. To do
|
||||||
that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph
|
that, simply add this crate as a Cargo dependency (it doesn't matter where in the dependency graph
|
||||||
this crate ends up, as long as it's there):
|
this crate ends up, as long as it's there):
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ environment:
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- git submodule update --init
|
||||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs
|
- curl -sSf -o rustup-init.exe https://win.rustup.rs
|
||||||
- rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y
|
- rustup-init.exe --default-host %TARGET% --default-toolchain nightly -y
|
||||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||||
|
|
1
build.rs
1
build.rs
|
@ -4,4 +4,5 @@ fn main() {
|
||||||
if env::var("TARGET").unwrap().ends_with("gnueabihf") {
|
if env::var("TARGET").unwrap().ends_with("gnueabihf") {
|
||||||
println!("cargo:rustc-cfg=gnueabihf")
|
println!("cargo:rustc-cfg=gnueabihf")
|
||||||
}
|
}
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
|
||||||
|
qemu-user-static
|
||||||
|
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,10 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-arm-linux-gnueabi libc6-dev-armel-cross qemu-user-static
|
||||||
|
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABI_LINKER=arm-linux-gnueabi-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/arm-linux-gnueabi \
|
||||||
|
RUST_TEST_THREADS=1
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static
|
||||||
|
ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,9 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user-static
|
||||||
|
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,5 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib libc6-dev ca-certificates
|
||||||
|
ENV PATH=$PATH:/rust/bin
|
|
@ -0,0 +1,5 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc-multilib libc6-dev ca-certificates
|
||||||
|
ENV PATH=$PATH:/rust/bin
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-mips-linux-gnu libc6-dev-mips-cross \
|
||||||
|
binfmt-support qemu-user-static qemu-system-mips
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/mips-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-mipsel-linux-gnu libc6-dev-mipsel-cross \
|
||||||
|
binfmt-support qemu-user-static
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_LINKER=mipsel-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/mipsel-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev qemu-user-static ca-certificates \
|
||||||
|
gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \
|
||||||
|
qemu-system-ppc
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/powerpc-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates \
|
||||||
|
gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \
|
||||||
|
binfmt-support qemu-user-static qemu-system-ppc
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \
|
||||||
|
CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev qemu-user-static ca-certificates \
|
||||||
|
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross \
|
||||||
|
qemu-system-ppc
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_LINKER=powerpc64le-linux-gnu-gcc \
|
||||||
|
CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
|
||||||
|
PATH=$PATH:/rust/bin \
|
||||||
|
QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu \
|
||||||
|
RUST_TEST_THREADS=1
|
|
@ -0,0 +1,6 @@
|
||||||
|
FROM ubuntu:16.04
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
gcc libc6-dev ca-certificates
|
||||||
|
ENV PATH=$PATH:/rust/bin
|
||||||
|
|
51
ci/env.sh
51
ci/env.sh
|
@ -1,51 +0,0 @@
|
||||||
case $TRAVIS_OS_NAME in
|
|
||||||
linux)
|
|
||||||
HOST=x86_64-unknown-linux-gnu
|
|
||||||
NM=nm
|
|
||||||
OBJDUMP=objdump
|
|
||||||
LINUX=y
|
|
||||||
;;
|
|
||||||
osx)
|
|
||||||
HOST=x86_64-apple-darwin
|
|
||||||
NM=gnm
|
|
||||||
OBJDUMP=gobjdump
|
|
||||||
OSX=y
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# NOTE For rustup
|
|
||||||
export PATH="$HOME/.cargo/bin:$PATH"
|
|
||||||
|
|
||||||
CARGO=cargo
|
|
||||||
RUN_TESTS=y
|
|
||||||
|
|
||||||
# NOTE For the host and its 32-bit variants we don't need prefixed tools or QEMU
|
|
||||||
if [[ $TARGET != $HOST && ! $TARGET =~ ^i.86- ]]; then
|
|
||||||
GCC_TRIPLE=${TARGET//unknown-/}
|
|
||||||
|
|
||||||
case $TARGET in
|
|
||||||
armv7-unknown-linux-gnueabihf)
|
|
||||||
GCC_TRIPLE=arm-linux-gnueabihf
|
|
||||||
;;
|
|
||||||
powerpc64le-unknown-linux-gnu)
|
|
||||||
# QEMU crashes even when executing the simplest cross compiled C program:
|
|
||||||
# `int main() { return 0; }`
|
|
||||||
RUN_TESTS=n
|
|
||||||
;;
|
|
||||||
thumbv*-none-eabi*)
|
|
||||||
CARGO=xargo
|
|
||||||
GCC_TRIPLE=arm-none-eabi
|
|
||||||
# Bare metal targets. No `std` or `test` crates for these targets.
|
|
||||||
RUN_TESTS=n
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
export CARGO_TARGET_$(echo $TARGET | tr a-z- A-Z_)_LINKER=$GCC_TRIPLE-gcc
|
|
||||||
|
|
||||||
if [[ $RUN_TESTS == y ]]; then
|
|
||||||
# NOTE(export) so this can reach the processes that `cargo test` spawns
|
|
||||||
export QEMU_LD_PREFIX=/usr/$GCC_TRIPLE
|
|
||||||
fi
|
|
||||||
|
|
||||||
PREFIX=$GCC_TRIPLE-
|
|
||||||
fi
|
|
|
@ -1,53 +0,0 @@
|
||||||
set -ex
|
|
||||||
|
|
||||||
. $(dirname $0)/env.sh
|
|
||||||
|
|
||||||
install_qemu() {
|
|
||||||
if [[ $QEMU_LD_PREFIX ]]; then
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
binfmt-support qemu-user-static
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_gist() {
|
|
||||||
if [[ $OSX ]]; then
|
|
||||||
gem install gist -v 4.5.0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_binutils() {
|
|
||||||
if [[ $OSX ]]; then
|
|
||||||
brew install binutils
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_rust() {
|
|
||||||
if [[ $OSX ]]; then
|
|
||||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=nightly
|
|
||||||
else
|
|
||||||
rustup default nightly
|
|
||||||
fi
|
|
||||||
|
|
||||||
rustup -V
|
|
||||||
rustc -V
|
|
||||||
cargo -V
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rustup_target() {
|
|
||||||
if [[ $TARGET != $HOST && $CARGO == cargo ]]; then
|
|
||||||
rustup target add $TARGET
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
if [[ $OSX || ${IN_DOCKER_CONTAINER:-n} == y ]]; then
|
|
||||||
install_qemu
|
|
||||||
install_gist
|
|
||||||
install_binutils
|
|
||||||
install_rust
|
|
||||||
add_rustup_target
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Small script to run tests for a target (or all targets) inside all the
|
||||||
|
# respective docker images.
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
run() {
|
||||||
|
echo $1
|
||||||
|
CMD="cargo test --target $1"
|
||||||
|
if [ "$NO_RUN" = "1" ]; then
|
||||||
|
CMD="$CMD --no-run"
|
||||||
|
fi
|
||||||
|
docker build -t libc ci/docker/$1
|
||||||
|
docker run \
|
||||||
|
-v `rustc --print sysroot`:/rust:ro \
|
||||||
|
-v `pwd`:/checkout:ro \
|
||||||
|
-e CARGO_TARGET_DIR=/tmp/target \
|
||||||
|
-w /checkout \
|
||||||
|
--privileged \
|
||||||
|
-it libc \
|
||||||
|
bash -c "$CMD && $CMD --release"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
for d in `ls ci/docker/`; do
|
||||||
|
run $d
|
||||||
|
done
|
||||||
|
else
|
||||||
|
run $1
|
||||||
|
fi
|
80
ci/script.sh
80
ci/script.sh
|
@ -1,80 +0,0 @@
|
||||||
set -ex
|
|
||||||
|
|
||||||
. $(dirname $0)/env.sh
|
|
||||||
|
|
||||||
gist_it() {
|
|
||||||
gist -d "'$TARGET/rustc-builtins.rlib' from commit '$TRAVIS_COMMIT' on branch '$TRAVIS_BRANCH'"
|
|
||||||
echo "Disassembly available at the above URL."
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
if [[ $WEAK ]]; then
|
|
||||||
$CARGO build --features weak --target $TARGET
|
|
||||||
$CARGO build --features weak --target $TARGET --release
|
|
||||||
else
|
|
||||||
$CARGO build --target $TARGET
|
|
||||||
$CARGO build --target $TARGET --release
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
inspect() {
|
|
||||||
$PREFIX$NM -g --defined-only target/**/debug/*.rlib
|
|
||||||
|
|
||||||
set +e
|
|
||||||
$PREFIX$OBJDUMP -Cd target/**/release/*.rlib | gist_it
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Check presence/absence of weak symbols
|
|
||||||
if [[ $WEAK ]]; then
|
|
||||||
local symbols=( memcmp memcpy memmove memset )
|
|
||||||
for symbol in "${symbols[@]}"; do
|
|
||||||
$PREFIX$NM target/$TARGET/debug/deps/librlibc-*.rlib | grep -q "W $symbol"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
set +e
|
|
||||||
ls target/$TARGET/debug/deps/librlibc-*.rlib
|
|
||||||
|
|
||||||
if [[ $? == 0 ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -e
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
run_tests() {
|
|
||||||
if [[ $QEMU_LD_PREFIX ]]; then
|
|
||||||
export RUST_TEST_THREADS=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $RUN_TESTS == y ]]; then
|
|
||||||
cargo test --target $TARGET
|
|
||||||
cargo test --target $TARGET --release
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
if [[ $LINUX && ${IN_DOCKER_CONTAINER:-n} == n ]]; then
|
|
||||||
# NOTE The Dockerfile of this image is in the docker branch of this repository
|
|
||||||
docker run \
|
|
||||||
--privileged \
|
|
||||||
-e IN_DOCKER_CONTAINER=y \
|
|
||||||
-e TARGET=$TARGET \
|
|
||||||
-e TRAVIS_BRANCH=$TRAVIS_BRANCH \
|
|
||||||
-e TRAVIS_COMMIT=$TRAVIS_COMMIT \
|
|
||||||
-e TRAVIS_OS_NAME=$TRAVIS_OS_NAME \
|
|
||||||
-e WEAK=$WEAK \
|
|
||||||
-v $(pwd):/mnt \
|
|
||||||
japaric/rustc-builtins \
|
|
||||||
sh -c 'cd /mnt;
|
|
||||||
bash ci/install.sh;
|
|
||||||
bash ci/script.sh'
|
|
||||||
else
|
|
||||||
build
|
|
||||||
inspect
|
|
||||||
run_tests
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "compiler-rt"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
compiler-rt-cdylib = { path = "compiler-rt-cdylib" }
|
||||||
|
libloading = "0.3"
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "compiler-rt-cdylib"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
gcc = "0.3"
|
|
@ -0,0 +1,68 @@
|
||||||
|
extern crate gcc;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
struct Sources {
|
||||||
|
files: Vec<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sources {
|
||||||
|
fn new() -> Sources {
|
||||||
|
Sources { files: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend(&mut self, sources: &[&'static str]) {
|
||||||
|
self.files.extend(sources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if !Path::new("compiler-rt/.git").exists() {
|
||||||
|
let _ = Command::new("git").args(&["submodule", "update", "--init"])
|
||||||
|
.status();
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = env::var("TARGET").expect("TARGET was not set");
|
||||||
|
let cfg = &mut gcc::Config::new();
|
||||||
|
|
||||||
|
if target.contains("msvc") {
|
||||||
|
cfg.define("__func__", Some("__FUNCTION__"));
|
||||||
|
} else {
|
||||||
|
cfg.flag("-fno-builtin");
|
||||||
|
cfg.flag("-fomit-frame-pointer");
|
||||||
|
cfg.flag("-ffreestanding");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sources = Sources::new();
|
||||||
|
|
||||||
|
sources.extend(&[
|
||||||
|
"muldi3.c",
|
||||||
|
"mulosi4.c",
|
||||||
|
"mulodi4.c",
|
||||||
|
"divsi3.c",
|
||||||
|
"divdi3.c",
|
||||||
|
"modsi3.c",
|
||||||
|
"moddi3.c",
|
||||||
|
"divmodsi4.c",
|
||||||
|
"divmoddi4.c",
|
||||||
|
"ashldi3.c",
|
||||||
|
"ashrdi3.c",
|
||||||
|
"lshrdi3.c",
|
||||||
|
"udivdi3.c",
|
||||||
|
"umoddi3.c",
|
||||||
|
"udivmoddi4.c",
|
||||||
|
"udivsi3.c",
|
||||||
|
"umodsi3.c",
|
||||||
|
"udivmodsi4.c",
|
||||||
|
"adddf3.c",
|
||||||
|
"addsf3.c",
|
||||||
|
]);
|
||||||
|
|
||||||
|
for src in sources.files.iter() {
|
||||||
|
cfg.file(Path::new("compiler-rt/lib/builtins").join(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.compile("libcompiler-rt.a");
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 515106ebc07227b85336816ef77bc39506b8fd26
|
|
@ -0,0 +1,60 @@
|
||||||
|
#![feature(lang_items)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn __ashldi3();
|
||||||
|
fn __ashrdi3();
|
||||||
|
fn __divdi3();
|
||||||
|
fn __divmoddi4();
|
||||||
|
fn __divmodsi4();
|
||||||
|
fn __divsi3();
|
||||||
|
fn __lshrdi3();
|
||||||
|
fn __moddi3();
|
||||||
|
fn __modsi3();
|
||||||
|
fn __muldi3();
|
||||||
|
fn __mulodi4();
|
||||||
|
fn __mulosi4();
|
||||||
|
fn __udivdi3();
|
||||||
|
fn __udivmoddi4();
|
||||||
|
fn __udivmodsi4();
|
||||||
|
fn __udivsi3();
|
||||||
|
fn __umoddi3();
|
||||||
|
fn __umodsi3();
|
||||||
|
fn __addsf3();
|
||||||
|
fn __adddf3();
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! declare {
|
||||||
|
($func:ident, $sym:ident) => {
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn $func() -> usize {
|
||||||
|
$sym as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare!(___ashldi3, __ashldi3);
|
||||||
|
declare!(___ashrdi3, __ashrdi3);
|
||||||
|
declare!(___divdi3, __divdi3);
|
||||||
|
declare!(___divmoddi4, __divmoddi4);
|
||||||
|
declare!(___divmodsi4, __divmodsi4);
|
||||||
|
declare!(___divsi3, __divsi3);
|
||||||
|
declare!(___lshrdi3, __lshrdi3);
|
||||||
|
declare!(___moddi3, __moddi3);
|
||||||
|
declare!(___modsi3, __modsi3);
|
||||||
|
declare!(___muldi3, __muldi3);
|
||||||
|
declare!(___mulodi4, __mulodi4);
|
||||||
|
declare!(___mulosi4, __mulosi4);
|
||||||
|
declare!(___udivdi3, __udivdi3);
|
||||||
|
declare!(___udivmoddi4, __udivmoddi4);
|
||||||
|
declare!(___udivmodsi4, __udivmodsi4);
|
||||||
|
declare!(___udivsi3, __udivsi3);
|
||||||
|
declare!(___umoddi3, __umoddi3);
|
||||||
|
declare!(___umodsi3, __umodsi3);
|
||||||
|
declare!(___addsf3, __addsf3);
|
||||||
|
declare!(___adddf3, __adddf3);
|
||||||
|
|
||||||
|
#[lang = "eh_personality"]
|
||||||
|
fn eh_personality() {}
|
||||||
|
#[lang = "panic_fmt"]
|
||||||
|
fn panic_fmt() {}
|
|
@ -0,0 +1,35 @@
|
||||||
|
#![feature(drop_types_in_const)]
|
||||||
|
|
||||||
|
extern crate libloading;
|
||||||
|
|
||||||
|
use std::sync::{Once, ONCE_INIT};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use libloading::Library;
|
||||||
|
|
||||||
|
fn compiler_rt() -> &'static Library {
|
||||||
|
let dir = env::current_exe().unwrap();
|
||||||
|
let cdylib = dir.parent().unwrap().read_dir().unwrap().map(|c| {
|
||||||
|
c.unwrap().path()
|
||||||
|
}).find(|path| {
|
||||||
|
path.file_name().unwrap().to_str().unwrap().contains("compiler_rt_cdylib")
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
static mut COMPILER_RT: Option<Library> = None;
|
||||||
|
static INIT: Once = ONCE_INIT;
|
||||||
|
|
||||||
|
INIT.call_once(|| {
|
||||||
|
COMPILER_RT = Some(Library::new(&cdylib).unwrap());
|
||||||
|
});
|
||||||
|
COMPILER_RT.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(sym: &str) -> usize {
|
||||||
|
unsafe {
|
||||||
|
let sym = format!("_{}", sym);
|
||||||
|
let f: fn() -> usize = *compiler_rt().get(sym.as_bytes()).unwrap();
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,42 +27,13 @@ fn gcc_s() -> &'static Library {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
macro_rules! declare {
|
pub fn get(_sym: &str) -> Option<usize> {
|
||||||
($symbol:ident: fn($($i:ty),+) -> $o:ty) => {
|
None
|
||||||
pub fn $symbol() -> Option<unsafe extern fn($($i),+) -> $o> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
macro_rules! declare {
|
pub fn get(sym: &str) -> Option<usize> {
|
||||||
($symbol:ident: fn($($i:ty),+) -> $o:ty) => {
|
unsafe {
|
||||||
pub fn $symbol() -> Option<unsafe extern fn($($i),+) -> $o> {
|
gcc_s().get(sym.as_bytes()).ok().map(|s| *s)
|
||||||
unsafe {
|
|
||||||
gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare!(ashldi3: fn(u64, u32) -> u64);
|
|
||||||
declare!(ashrdi3: fn(i64, u32) -> i64);
|
|
||||||
declare!(divdi3: fn(i64, i64) -> i64);
|
|
||||||
declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64);
|
|
||||||
declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32);
|
|
||||||
declare!(divsi3: fn(i32, i32) -> i32);
|
|
||||||
declare!(lshrdi3: fn(u64, u32) -> u64);
|
|
||||||
declare!(moddi3: fn(i64, i64) -> i64);
|
|
||||||
declare!(modsi3: fn(i32, i32) -> i32);
|
|
||||||
declare!(muldi3: fn(u64, u64) -> u64);
|
|
||||||
declare!(mulodi4: fn(i64, i64, &mut i32) -> i64);
|
|
||||||
declare!(mulosi4: fn(i32, i32, &mut i32) -> i32);
|
|
||||||
declare!(udivdi3: fn(u64, u64) -> u64);
|
|
||||||
declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64);
|
|
||||||
declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32);
|
|
||||||
declare!(udivsi3: fn(u32, u32) -> u32);
|
|
||||||
declare!(umoddi3: fn(u64, u64) -> u64);
|
|
||||||
declare!(umodsi3: fn(u32, u32) -> u32);
|
|
||||||
declare!(addsf3: fn(f32, f32) -> f32);
|
|
||||||
declare!(adddf3: fn(f64, f64) -> f64);
|
|
||||||
|
|
|
@ -190,44 +190,43 @@ mod tests {
|
||||||
use float::Float;
|
use float::Float;
|
||||||
use qc::{U32, U64};
|
use qc::{U32, U64};
|
||||||
|
|
||||||
use gcc_s;
|
|
||||||
use rand;
|
|
||||||
|
|
||||||
// NOTE The tests below have special handing for NaN values.
|
// NOTE The tests below have special handing for NaN values.
|
||||||
// Because NaN != NaN, the floating-point representations must be used
|
// Because NaN != NaN, the floating-point representations must be used
|
||||||
// Because there are many diffferent values of NaN, and the implementation
|
// Because there are many diffferent values of NaN, and the implementation
|
||||||
// doesn't care about calculating the 'correct' one, if both values are NaN
|
// doesn't care about calculating the 'correct' one, if both values are NaN
|
||||||
// the values are considered equivalent.
|
// the values are considered equivalent.
|
||||||
|
|
||||||
// TODO: Add F32/F64 to qc so that they print the right values (at the very least)
|
struct FRepr<F>(F);
|
||||||
quickcheck! {
|
|
||||||
fn addsf3(a: U32, b: U32) -> bool {
|
|
||||||
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
|
|
||||||
let x = super::__addsf3(a, b);
|
|
||||||
|
|
||||||
match gcc_s::addsf3() {
|
impl<F: Float> PartialEq for FRepr<F> {
|
||||||
// NOTE(cfg) for some reason, on hard float targets, our implementation doesn't
|
fn eq(&self, other: &FRepr<F>) -> bool {
|
||||||
// match the output of its gcc_s counterpart. Until we investigate further, we'll
|
// NOTE(cfg) for some reason, on hard float targets, our implementation doesn't
|
||||||
// just avoid testing against gcc_s on those targets. Do note that our
|
// match the output of its gcc_s counterpart. Until we investigate further, we'll
|
||||||
// implementation matches the output of the FPU instruction on *hard* float targets
|
// just avoid testing against gcc_s on those targets. Do note that our
|
||||||
// and matches its gcc_s counterpart on *soft* float targets.
|
// implementation matches the output of the FPU instruction on *hard* float targets
|
||||||
#[cfg(not(gnueabihf))]
|
// and matches its gcc_s counterpart on *soft* float targets.
|
||||||
Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }),
|
if cfg!(gnueabihf) {
|
||||||
_ => x.eq_repr(a + b),
|
return true
|
||||||
}
|
}
|
||||||
|
self.0.eq_repr(other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add F32/F64 to qc so that they print the right values (at the very least)
|
||||||
|
check! {
|
||||||
|
fn __addsf3(f: extern fn(f32, f32) -> f32,
|
||||||
|
a: U32,
|
||||||
|
b: U32)
|
||||||
|
-> Option<FRepr<f32> > {
|
||||||
|
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
|
||||||
|
Some(FRepr(f(a, b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adddf3(a: U64, b: U64) -> bool {
|
fn __adddf3(f: extern fn(f64, f64) -> f64,
|
||||||
|
a: U64,
|
||||||
|
b: U64) -> Option<FRepr<f64> > {
|
||||||
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
|
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
|
||||||
let x = super::__adddf3(a, b);
|
Some(FRepr(f(a, b)))
|
||||||
|
|
||||||
match gcc_s::adddf3() {
|
|
||||||
// NOTE(cfg) See NOTE above
|
|
||||||
#[cfg(not(gnueabihf))]
|
|
||||||
Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }),
|
|
||||||
_ => x.eq_repr(a + b),
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use core::mem;
|
||||||
pub mod add;
|
pub mod add;
|
||||||
|
|
||||||
/// Trait for some basic operations on floats
|
/// Trait for some basic operations on floats
|
||||||
pub trait Float: Sized {
|
pub trait Float: Sized + Copy {
|
||||||
/// A uint of the same with as the float
|
/// A uint of the same with as the float
|
||||||
type Int;
|
type Int;
|
||||||
|
|
||||||
|
|
|
@ -74,60 +74,34 @@ mulo!(__mulodi4: i64);
|
||||||
mod tests {
|
mod tests {
|
||||||
use qc::{I32, I64, U64};
|
use qc::{I32, I64, U64};
|
||||||
|
|
||||||
use gcc_s;
|
check! {
|
||||||
use rand;
|
fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64)
|
||||||
|
-> Option<u64> {
|
||||||
quickcheck! {
|
Some(f(a.0, b.0))
|
||||||
fn muldi(a: U64, b: U64) -> bool {
|
|
||||||
let (a, b) = (a.0, b.0);
|
|
||||||
let r = super::__muldi3(a, b);
|
|
||||||
|
|
||||||
match gcc_s::muldi3() {
|
|
||||||
Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) },
|
|
||||||
_ => r == a.wrapping_mul(b),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mulosi(a: I32, b: I32) -> bool {
|
fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32,
|
||||||
|
a: I32,
|
||||||
|
b: I32) -> Option<(i32, i32)> {
|
||||||
let (a, b) = (a.0, b.0);
|
let (a, b) = (a.0, b.0);
|
||||||
let mut overflow = 2;
|
let mut overflow = 2;
|
||||||
let r = super::__mulosi4(a, b, &mut overflow);
|
let r = f(a, b, &mut overflow);
|
||||||
if overflow != 0 && overflow != 1 {
|
if overflow != 0 && overflow != 1 {
|
||||||
return false;
|
return None
|
||||||
}
|
|
||||||
|
|
||||||
match gcc_s::mulosi4() {
|
|
||||||
Some(mulosi4) if rand::random() => {
|
|
||||||
let mut gcc_s_overflow = 2;
|
|
||||||
let gcc_s_r = unsafe {
|
|
||||||
mulosi4(a, b, &mut gcc_s_overflow)
|
|
||||||
};
|
|
||||||
|
|
||||||
(r, overflow) == (gcc_s_r, gcc_s_overflow)
|
|
||||||
},
|
|
||||||
_ => (r, overflow != 0) == a.overflowing_mul(b),
|
|
||||||
}
|
}
|
||||||
|
Some((r, overflow))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mulodi(a: I64, b: I64) -> bool {
|
fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64,
|
||||||
|
a: I64,
|
||||||
|
b: I64) -> Option<(i64, i32)> {
|
||||||
let (a, b) = (a.0, b.0);
|
let (a, b) = (a.0, b.0);
|
||||||
let mut overflow = 2;
|
let mut overflow = 2;
|
||||||
let r = super::__mulodi4(a, b, &mut overflow);
|
let r = f(a, b, &mut overflow);
|
||||||
if overflow != 0 && overflow != 1 {
|
if overflow != 0 && overflow != 1 {
|
||||||
return false;
|
return None
|
||||||
}
|
|
||||||
|
|
||||||
match gcc_s::mulodi4() {
|
|
||||||
Some(mulodi4) if rand::random() => {
|
|
||||||
let mut gcc_s_overflow = 2;
|
|
||||||
let gcc_s_r = unsafe {
|
|
||||||
mulodi4(a, b, &mut gcc_s_overflow)
|
|
||||||
};
|
|
||||||
|
|
||||||
(r, overflow) == (gcc_s_r, gcc_s_overflow)
|
|
||||||
},
|
|
||||||
_ => (r, overflow != 0) == a.overflowing_mul(b),
|
|
||||||
}
|
}
|
||||||
|
Some((r, overflow))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
104
src/int/sdiv.rs
104
src/int/sdiv.rs
|
@ -54,116 +54,70 @@ divmod!(__divmoddi4, __divdi3: i64);
|
||||||
mod tests {
|
mod tests {
|
||||||
use qc::{U32, U64};
|
use qc::{U32, U64};
|
||||||
|
|
||||||
use gcc_s;
|
check! {
|
||||||
use quickcheck::TestResult;
|
fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
||||||
use rand;
|
|
||||||
|
|
||||||
quickcheck!{
|
|
||||||
fn divdi3(n: U64, d: U64) -> TestResult {
|
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let q = super::__divdi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::divdi3() {
|
|
||||||
Some(divdi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(q == unsafe { divdi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn moddi3(n: U64, d: U64) -> TestResult {
|
fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__moddi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::moddi3() {
|
|
||||||
Some(moddi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { moddi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divmoddi4(n: U64, d: U64) -> TestResult {
|
fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64,
|
||||||
|
n: U64,
|
||||||
|
d: U64) -> Option<(i64, i64)> {
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut r = 0;
|
let mut r = 0;
|
||||||
let q = super::__divmoddi4(n, d, &mut r);
|
let q = f(n, d, &mut r);
|
||||||
|
Some((q, r))
|
||||||
match gcc_s::divmoddi4() {
|
|
||||||
Some(divmoddi4) if rand::random() => {
|
|
||||||
let mut gcc_s_r = 0;
|
|
||||||
let gcc_s_q = unsafe {
|
|
||||||
divmoddi4(n, d, &mut gcc_s_r)
|
|
||||||
};
|
|
||||||
|
|
||||||
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d && r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divsi3(n: U32, d: U32) -> TestResult {
|
fn __divsi3(f: extern fn(i32, i32) -> i32,
|
||||||
|
n: U32,
|
||||||
|
d: U32) -> Option<i32> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let q = super::__divsi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::divsi3() {
|
|
||||||
Some(divsi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(q == unsafe { divsi3(n, d)})
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modsi3(n: U32, d: U32) -> TestResult {
|
fn __modsi3(f: extern fn(i32, i32) -> i32,
|
||||||
|
n: U32,
|
||||||
|
d: U32) -> Option<i32> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__modsi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::modsi3() {
|
|
||||||
Some(modsi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { modsi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divmodsi4(n: U32, d: U32) -> TestResult {
|
fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32,
|
||||||
|
n: U32,
|
||||||
|
d: U32) -> Option<(i32, i32)> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut r = 0;
|
let mut r = 0;
|
||||||
let q = super::__divmodsi4(n, d, &mut r);
|
let q = f(n, d, &mut r);
|
||||||
|
Some((q, r))
|
||||||
match gcc_s::divmodsi4() {
|
|
||||||
Some(divmodsi4) if rand::random() => {
|
|
||||||
let mut gcc_s_r = 0;
|
|
||||||
let gcc_s_q = unsafe {
|
|
||||||
divmodsi4(n, d, &mut gcc_s_r)
|
|
||||||
};
|
|
||||||
|
|
||||||
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d && r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,57 +62,32 @@ lshr!(__lshrdi3: u64);
|
||||||
mod tests {
|
mod tests {
|
||||||
use qc::{I64, U64};
|
use qc::{I64, U64};
|
||||||
|
|
||||||
use gcc_s;
|
|
||||||
use quickcheck::TestResult;
|
|
||||||
use rand;
|
|
||||||
|
|
||||||
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
||||||
quickcheck! {
|
check! {
|
||||||
fn ashldi(a: U64, b: u32) -> TestResult {
|
fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__ashldi3(a, b);
|
Some(f(a, b))
|
||||||
|
|
||||||
match gcc_s::ashldi3() {
|
|
||||||
Some(ashldi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { ashldi3(a, b) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == a << b),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ashrdi(a: I64, b: u32) -> TestResult {
|
fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__ashrdi3(a, b);
|
Some(f(a, b))
|
||||||
|
|
||||||
match gcc_s::ashrdi3() {
|
|
||||||
Some(ashrdi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { ashrdi3(a, b) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == a >> b),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lshrdi(a: U64, b: u32) -> TestResult {
|
fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__lshrdi3(a, b);
|
Some(f(a, b))
|
||||||
|
|
||||||
match gcc_s::lshrdi3() {
|
|
||||||
Some(lshrdi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { lshrdi3(a, b) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == a >> b),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
100
src/int/udiv.rs
100
src/int/udiv.rs
|
@ -230,116 +230,66 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
mod tests {
|
mod tests {
|
||||||
use qc::{U32, U64};
|
use qc::{U32, U64};
|
||||||
|
|
||||||
use gcc_s;
|
check! {
|
||||||
use quickcheck::TestResult;
|
fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
||||||
use rand;
|
|
||||||
|
|
||||||
quickcheck!{
|
|
||||||
fn udivdi3(n: U64, d: U64) -> TestResult {
|
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let q = super::__udivdi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::udivdi3() {
|
|
||||||
Some(udivdi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(q == unsafe { udivdi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn umoddi3(n: U64, d: U64) -> TestResult {
|
fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__umoddi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::umoddi3() {
|
|
||||||
Some(umoddi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { umoddi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn udivmoddi4(n: U64, d: U64) -> TestResult {
|
fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64,
|
||||||
|
n: U64,
|
||||||
|
d: U64) -> Option<(u64, u64)> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut r = 0;
|
let mut r = 0;
|
||||||
let q = super::__udivmoddi4(n, d, Some(&mut r));
|
let q = f(n, d, Some(&mut r));
|
||||||
|
Some((q, r))
|
||||||
match gcc_s::udivmoddi4() {
|
|
||||||
Some(udivmoddi4) if rand::random() => {
|
|
||||||
let mut gcc_s_r = 0;
|
|
||||||
let gcc_s_q = unsafe {
|
|
||||||
udivmoddi4(n, d, Some(&mut gcc_s_r))
|
|
||||||
};
|
|
||||||
|
|
||||||
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d && r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn udivsi3(n: U32, d: U32) -> TestResult {
|
fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let q = super::__udivsi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::udivsi3() {
|
|
||||||
Some(udivsi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(q == unsafe { udivsi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn umodsi3(n: U32, d: U32) -> TestResult {
|
fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let r = super::__umodsi3(n, d);
|
Some(f(n, d))
|
||||||
|
|
||||||
match gcc_s::umodsi3() {
|
|
||||||
Some(umodsi3) if rand::random() => {
|
|
||||||
TestResult::from_bool(r == unsafe { umodsi3(n, d) })
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn udivmodsi4(n: U32, d: U32) -> TestResult {
|
fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32,
|
||||||
|
n: U32,
|
||||||
|
d: U32) -> Option<(u32, u32)> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
TestResult::discard()
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut r = 0;
|
let mut r = 0;
|
||||||
let q = super::__udivmodsi4(n, d, Some(&mut r));
|
let q = f(n, d, Some(&mut r));
|
||||||
|
Some((q, r))
|
||||||
match gcc_s::udivmodsi4() {
|
|
||||||
Some(udivmodsi4) if rand::random() => {
|
|
||||||
let mut gcc_s_r = 0;
|
|
||||||
let gcc_s_q = unsafe {
|
|
||||||
udivmodsi4(n, d, Some(&mut gcc_s_r))
|
|
||||||
};
|
|
||||||
|
|
||||||
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
|
|
||||||
},
|
|
||||||
_ => TestResult::from_bool(q == n / d && r == n % d),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -20,12 +20,19 @@ extern crate core;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate gcc_s;
|
extern crate gcc_s;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
extern crate compiler_rt;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
#[cfg(feature = "weak")]
|
#[cfg(feature = "weak")]
|
||||||
extern crate rlibc;
|
extern crate rlibc;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
mod qc;
|
||||||
|
|
||||||
pub mod int;
|
pub mod int;
|
||||||
pub mod float;
|
pub mod float;
|
||||||
|
|
||||||
|
@ -34,7 +41,3 @@ pub mod arm;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod qc;
|
|
||||||
|
|
||||||
|
|
121
src/qc.rs
121
src/qc.rs
|
@ -142,3 +142,124 @@ macro_rules! arbitrary_large {
|
||||||
|
|
||||||
arbitrary_large!(I64: i64);
|
arbitrary_large!(I64: i64);
|
||||||
arbitrary_large!(U64: u64);
|
arbitrary_large!(U64: u64);
|
||||||
|
|
||||||
|
// Convenience macro to test intrinsics against their reference implementations.
|
||||||
|
//
|
||||||
|
// Each intrinsic is tested against both the `gcc_s` library as well as
|
||||||
|
// `compiler-rt`. These libraries are defined in the `gcc_s` crate as well as
|
||||||
|
// the `compiler-rt` crate in this repository. Both load a dynamic library and
|
||||||
|
// lookup symbols through that dynamic library to ensure that we're using the
|
||||||
|
// right intrinsic.
|
||||||
|
//
|
||||||
|
// This macro hopefully allows you to define a bare minimum of how to test an
|
||||||
|
// intrinsic without worrying about these implementation details. A sample
|
||||||
|
// invocation looks like:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// check! {
|
||||||
|
// // First argument is the function we're testing (either from this lib
|
||||||
|
// // or a dynamically loaded one. Further arguments are all generated by
|
||||||
|
// // quickcheck.
|
||||||
|
// fn __my_intrinsic(f: extern fn(i32) -> i32,
|
||||||
|
// a: I32)
|
||||||
|
// -> Option<(i32, i64)> {
|
||||||
|
//
|
||||||
|
// // Discard tests by returning Some
|
||||||
|
// if a.0 == 0 {
|
||||||
|
// return None
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Return the result via `Some` if the test can run
|
||||||
|
// let mut other_result = 0;
|
||||||
|
// let result = f(a.0, &mut other_result);
|
||||||
|
// Some((result, other_result))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If anything returns `None` then the test is discarded, otherwise the two
|
||||||
|
// results are compared for equality and the test fails if this equality check
|
||||||
|
// fails.
|
||||||
|
macro_rules! check {
|
||||||
|
($(
|
||||||
|
fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty,
|
||||||
|
$($arg:ident: $t:ty),*)
|
||||||
|
-> Option<$ret:ty>
|
||||||
|
{
|
||||||
|
$($code:tt)*
|
||||||
|
}
|
||||||
|
)*) => (
|
||||||
|
$(
|
||||||
|
fn $name($f: extern fn($($farg),*) -> $fret,
|
||||||
|
$($arg: $t),*) -> Option<$ret> {
|
||||||
|
$($code)*
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
mod _compiler_rt {
|
||||||
|
use qc::*;
|
||||||
|
use std::mem;
|
||||||
|
use quickcheck::TestResult;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
fn my_check($($arg:$t),*) -> TestResult {
|
||||||
|
let my_answer = super::$name(super::super::$name,
|
||||||
|
$($arg),*);
|
||||||
|
let compiler_rt_fn = ::compiler_rt::get(stringify!($name));
|
||||||
|
unsafe {
|
||||||
|
let compiler_rt_answer =
|
||||||
|
super::$name(mem::transmute(compiler_rt_fn),
|
||||||
|
$($arg),*);
|
||||||
|
match (my_answer, compiler_rt_answer) {
|
||||||
|
(None, _) | (_, None) => TestResult::discard(),
|
||||||
|
(Some(a), Some(b)) => {
|
||||||
|
TestResult::from_bool(a == b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
mod _gcc_s {
|
||||||
|
use qc::*;
|
||||||
|
use std::mem;
|
||||||
|
use quickcheck::TestResult;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
fn my_check($($arg:$t),*) -> TestResult {
|
||||||
|
let my_answer = super::$name(super::super::$name,
|
||||||
|
$($arg),*);
|
||||||
|
let gcc_s_fn = ::gcc_s::get(stringify!($name)).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let gcc_s_answer =
|
||||||
|
super::$name(mem::transmute(gcc_s_fn),
|
||||||
|
$($arg),*);
|
||||||
|
match (my_answer, gcc_s_answer) {
|
||||||
|
(None, _) | (_, None) => TestResult::discard(),
|
||||||
|
(Some(a), Some(b)) => {
|
||||||
|
TestResult::from_bool(a == b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's not in libgcc, or we couldn't find libgcc, then
|
||||||
|
// just ignore this. We should have tests through
|
||||||
|
// compiler-rt in any case
|
||||||
|
if ::gcc_s::get(stringify!($name)).is_none() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
::quickcheck::quickcheck(my_check as fn($($t),*) -> TestResult)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
use core::intrinsics;
|
use core::intrinsics;
|
||||||
|
|
||||||
// NOTE These functions are implemented using assembly because they using a custom
|
// NOTE These functions are implemented using assembly because they using a custom
|
||||||
|
|
Loading…
Reference in New Issue