Browse Source

Merge pull request #155 from rust-lang-nursery/utest

no-std friendly test suite
Jorge Aparicio 8 years ago
parent
commit
7b98ecebfd
81 changed files with 4394 additions and 1419 deletions
  1. 0 11
      .cargo/config
  2. 1 1
      .gitmodules
  3. 5 7
      .travis.yml
  4. 11 10
      Cargo.toml
  5. 4 3
      appveyor.yml
  6. 3819 389
      build.rs
  7. 4 4
      ci/docker/thumbv6m-linux-eabi/Dockerfile
  8. 4 4
      ci/docker/thumbv7em-linux-eabi/Dockerfile
  9. 4 4
      ci/docker/thumbv7em-linux-eabihf/Dockerfile
  10. 4 4
      ci/docker/thumbv7m-linux-eabi/Dockerfile
  11. 30 4
      ci/run.sh
  12. 0 0
      compiler-rt
  13. 0 8
      compiler-rt/Cargo.toml
  14. 0 12
      compiler-rt/compiler-rt-cdylib/Cargo.toml
  15. 0 104
      compiler-rt/compiler-rt-cdylib/build.rs
  16. 0 126
      compiler-rt/compiler-rt-cdylib/src/lib.rs
  17. 0 35
      compiler-rt/src/lib.rs
  18. 0 7
      gcc_s/Cargo.toml
  19. 0 39
      gcc_s/src/lib.rs
  20. 0 81
      src/arm.rs
  21. 0 25
      src/float/add.rs
  22. 1 109
      src/float/conv.rs
  23. 0 19
      src/float/pow.rs
  24. 0 25
      src/float/sub.rs
  25. 0 63
      src/int/mul.rs
  26. 0 117
      src/int/sdiv.rs
  27. 0 74
      src/int/shift.rs
  28. 0 117
      src/int/udiv.rs
  29. 0 17
      src/lib.rs
  30. 8 0
      tests/adddf3.rs
  31. 8 0
      tests/addsf3.rs
  32. 8 0
      tests/ashldi3.rs
  33. 8 0
      tests/ashlti3.rs
  34. 8 0
      tests/ashrdi3.rs
  35. 8 0
      tests/ashrti3.rs
  36. 8 0
      tests/divdi3.rs
  37. 8 0
      tests/divmoddi4.rs
  38. 8 0
      tests/divmodsi4.rs
  39. 8 0
      tests/divsi3.rs
  40. 11 0
      tests/divti3.rs
  41. 8 0
      tests/fixdfdi.rs
  42. 8 0
      tests/fixdfsi.rs
  43. 8 0
      tests/fixsfdi.rs
  44. 8 0
      tests/fixsfsi.rs
  45. 8 0
      tests/fixunsdfdi.rs
  46. 8 0
      tests/fixunsdfsi.rs
  47. 8 0
      tests/fixunssfdi.rs
  48. 8 0
      tests/fixunssfsi.rs
  49. 8 0
      tests/floatdidf.rs
  50. 8 0
      tests/floatsidf.rs
  51. 8 0
      tests/floatsisf.rs
  52. 8 0
      tests/floatundidf.rs
  53. 8 0
      tests/floatunsidf.rs
  54. 8 0
      tests/floatunsisf.rs
  55. 8 0
      tests/lshrdi3.rs
  56. 8 0
      tests/lshrti3.rs
  57. 8 0
      tests/moddi3.rs
  58. 8 0
      tests/modsi3.rs
  59. 11 0
      tests/modti3.rs
  60. 8 0
      tests/muldi3.rs
  61. 8 0
      tests/mulodi4.rs
  62. 8 0
      tests/mulosi4.rs
  63. 10 0
      tests/muloti4.rs
  64. 8 0
      tests/multi3.rs
  65. 8 0
      tests/powidf2.rs
  66. 8 0
      tests/powisf2.rs
  67. 8 0
      tests/subdf3.rs
  68. 8 0
      tests/subsf3.rs
  69. 8 0
      tests/udivdi3.rs
  70. 8 0
      tests/udivmoddi4.rs
  71. 8 0
      tests/udivmodsi4.rs
  72. 11 0
      tests/udivmodti4.rs
  73. 8 0
      tests/udivsi3.rs
  74. 11 0
      tests/udivti3.rs
  75. 8 0
      tests/umoddi3.rs
  76. 8 0
      tests/umodsi3.rs
  77. 11 0
      tests/umodti3.rs
  78. 27 0
      thumbv6m-linux-eabi.json
  79. 26 0
      thumbv7em-linux-eabi.json
  80. 27 0
      thumbv7em-linux-eabihf.json
  81. 26 0
      thumbv7m-linux-eabi.json

+ 0 - 11
.cargo/config

@@ -1,11 +0,0 @@
-[target.thumbv6m-none-eabi]
-rustflags = ["-C", "link-arg=-nostartfiles"]
-
-[target.thumbv7m-none-eabi]
-rustflags = ["-C", "link-arg=-nostartfiles"]
-
-[target.thumbv7em-none-eabi]
-rustflags = ["-C", "link-arg=-nostartfiles"]
-
-[target.thumbv7em-none-eabihf]
-rustflags = ["-C", "link-arg=-nostartfiles"]

+ 1 - 1
.gitmodules

@@ -1,3 +1,3 @@
 [submodule "compiler-rt/compiler-rt-cdylib/compiler-rt"]
-	path = compiler-rt/compiler-rt-cdylib/compiler-rt
+	path = compiler-rt
 	url = https://github.com/rust-lang/compiler-rt

+ 5 - 7
.travis.yml

@@ -22,10 +22,10 @@ matrix:
     - env: TARGET=powerpc-unknown-linux-gnu
     - env: TARGET=powerpc64-unknown-linux-gnu
     - env: TARGET=powerpc64le-unknown-linux-gnu
-    - env: TARGET=thumbv6m-none-eabi
-    - env: TARGET=thumbv7em-none-eabi
-    - env: TARGET=thumbv7em-none-eabihf
-    - env: TARGET=thumbv7m-none-eabi
+    - env: TARGET=thumbv6m-linux-eabi
+    - env: TARGET=thumbv7em-linux-eabi
+    - env: TARGET=thumbv7em-linux-eabihf
+    - env: TARGET=thumbv7m-linux-eabi
     - env: TARGET=x86_64-apple-darwin
       os: osx
 env: TARGET=x86_64-unknown-linux-gnu
@@ -34,11 +34,9 @@ before_install:
   - test "$TRAVIS_OS_NAME" = "osx" || docker run --rm --privileged multiarch/qemu-user-static:register
 
 install:
-  - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
-  - source ~/.cargo/env
   - case $TARGET in
       x86_64-apple-darwin | x86_64-unknown-linux-gnu) ;;
-      thumbv*-none-eabi*) rustup component add rust-src ;;
+      thumbv*eabi*) rustup component add rust-src ;;
       *) rustup target add $TARGET;;
     esac
 

+ 11 - 10
Cargo.toml

@@ -5,26 +5,27 @@ name = "compiler_builtins"
 version = "0.1.0"
 
 [build-dependencies]
-rustc-cfg = "0.3.0"
+cast = { version = "0.2.0", optional = true }
+rand = { version = "0.3.15", optional = true }
 
 [build-dependencies.gcc]
 optional = true
 version = "0.3.36"
 
-[dev-dependencies]
-quickcheck = "0.3.1"
-rand = "0.3.14"
-gcc_s = { path = "gcc_s" }
-compiler-rt = { path = "compiler-rt" }
-
 [features]
-# Build the missing intrinsics from compiler-rt C source code
 c = ["gcc"]
-# Mark this crate as the #![compiler_builtins] crate
 compiler-builtins = []
 default = ["compiler-builtins"]
-# Include implementations of memory operations like memcpy
 mem = []
 rustbuild = ["compiler-builtins"]
+# generate tests
+gen-tests = ["cast", "rand"]
+
+[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies]
+test = { git = "https://github.com/japaric/utest" }
+utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" }
+utest-macros = { git = "https://github.com/japaric/utest" }
+
+
 
 [workspace]

+ 4 - 3
appveyor.yml

@@ -6,8 +6,9 @@ environment:
 install:
   - git submodule update --init
   - 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 x86_64-pc-windows-msvc --default-toolchain nightly -y
   - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+  - if "%TARGET%"=="i686-pc-windows-msvc" ( rustup target add %TARGET% )
   - rustc -Vv
   - cargo -V
 
@@ -16,5 +17,5 @@ build: false
 test_script:
   - cargo build --target %TARGET%
   - cargo build --release --target %TARGET%
-  - cargo test --no-default-features --target %TARGET%
-  - cargo test --no-default-features --release --target %TARGET%
+  - cargo test --no-default-features --features gen-tests --target %TARGET%
+  - cargo test --no-default-features --features gen-tests --release --target %TARGET%

+ 3819 - 389
build.rs

@@ -1,436 +1,3866 @@
-#[cfg(feature = "c")]
-extern crate gcc;
-extern crate rustc_cfg;
+#![feature(i128_type)]
+
+use std::env;
+
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+
+    let target = env::var("TARGET").unwrap();
+
+    // Emscripten's runtime includes all the builtins
+    if target.contains("emscripten") {
+        return;
+    }
+
+    // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
+    // target triple. This is usually correct for our built-in targets but can break in presence of
+    // custom targets, which can have arbitrary names.
+    let llvm_target = target.split('-').collect::<Vec<_>>();
+
+    // Build test files
+    #[cfg(feature = "gen-tests")]
+    tests::generate();
+
+    // Build missing intrinsics from compiler-rt C source code
+    #[cfg(feature = "c")]
+    c::compile(&llvm_target);
+
+    // To compile intrinsics.rs for thumb targets, where there is no libc
+    if llvm_target[0].starts_with("thumb") {
+        println!("cargo:rustc-cfg=thumb")
+    }
+
+    // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full
+    // THUMBv2 support. We have to cfg our code accordingly.
+    if llvm_target[0] == "thumbv6m" {
+        println!("cargo:rustc-cfg=thumbv6m")
+    }
+}
+
+#[cfg(feature = "gen-tests")]
+mod tests {
+    extern crate cast;
+    extern crate rand;
+
+    use std::collections::HashSet;
+    use std::fmt::Write;
+    use std::fs::File;
+    use std::hash::Hash;
+    use std::path::PathBuf;
+    use std::{env, mem};
+
+    use self::cast::{f32, f64, u32, u64, i32, i64};
+    use self::rand::Rng;
+
+    const NTESTS: usize = 10_000;
+
+    macro_rules! test {
+        ($($intrinsic:ident,)+) => {
+            $(
+                mk_file::<$intrinsic>();
+            )+
+        }
+    }
+
+    pub fn generate() {
+        // TODO move to main
+        test! {
+            // float/add.rs
+            Adddf3,
+            Addsf3,
+
+            // float/conv.rs
+            Fixdfdi,
+            Fixdfsi,
+            Fixsfdi,
+            Fixsfsi,
+            Fixunsdfdi,
+            Fixunsdfsi,
+            Fixunssfdi,
+            Fixunssfsi,
+            Floatdidf,
+            Floatsidf,
+            Floatsisf,
+            Floatundidf,
+            Floatunsidf,
+            Floatunsisf,
+
+            // float/pow.rs
+            Powidf2,
+            Powisf2,
+
+            // float/sub.rs
+            Subdf3,
+            Subsf3,
+
+            // int/mul.rs
+            Muldi3,
+            Mulodi4,
+            Mulosi4,
+            Muloti4,
+            Multi3,
+
+            // int/sdiv.rs
+            Divdi3,
+            Divmoddi4,
+            Divmodsi4,
+            Divsi3,
+            Divti3,
+            Moddi3,
+            Modsi3,
+            Modti3,
+
+            // int/shift.rs
+            Ashldi3,
+            Ashlti3,
+            Ashrdi3,
+            Ashrti3,
+            Lshrdi3,
+            Lshrti3,
+
+            // int/udiv.rs
+            Udivdi3,
+            Udivmoddi4,
+            Udivmodsi4,
+            Udivmodti4,
+            Udivsi3,
+            Udivti3,
+            Umoddi3,
+            Umodsi3,
+            Umodti3,
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Adddf3 {
+        a: u64,  // f64
+        b: u64,  // f64
+        c: u64,  // f64
+    }
+
+    impl TestCase for Adddf3 {
+        fn name() -> &'static str {
+            "adddf3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            let b = gen_f64(rng);
+            let c = a + b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Adddf3 {
+                    a: to_u64(a),
+                    b: to_u64(b),
+                    c: to_u64(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::add::__adddf3;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn adddf3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __adddf3(mk_f64(a), mk_f64(b));
+        assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Addsf3 {
+        a: u32,  // f32
+        b: u32,  // f32
+        c: u32,  // f32
+    }
+
+    impl TestCase for Addsf3 {
+        fn name() -> &'static str {
+            "addsf3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            let b = gen_f32(rng);
+            let c = a + b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Addsf3 {
+                    a: to_u32(a),
+                    b: to_u32(b),
+                    c: to_u32(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::add::__addsf3;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn addsf3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __addsf3(mk_f32(a), mk_f32(b));
+        assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Ashldi3 {
+        a: u64,
+        b: u32,
+        c: u64,
+    }
+
+    impl TestCase for Ashldi3 {
+        fn name() -> &'static str {
+            "ashldi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = (rng.gen::<u8>() % 64) as u32;
+            let c = a << b;
+
+            Some(Ashldi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__ashldi3;
+
+static TEST_CASES: &[((u64, u32), u64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn ashldi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __ashldi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Ashlti3 {
+        a: u128,
+        b: u32,
+        c: u128,
+    }
+
+    impl TestCase for Ashlti3 {
+        fn name() -> &'static str {
+            "ashlti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = (rng.gen::<u8>() % 128) as u32;
+            let c = a << b;
+
+            Some(Ashlti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__ashlti3;
+
+static TEST_CASES: &[((u128, u32), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn ashlti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __ashlti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Ashrdi3 {
+        a: i64,
+        b: u32,
+        c: i64,
+    }
+
+    impl TestCase for Ashrdi3 {
+        fn name() -> &'static str {
+            "ashrdi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i64(rng);
+            let b = (rng.gen::<u8>() % 64) as u32;
+            let c = a >> b;
+
+            Some(Ashrdi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__ashrdi3;
+
+static TEST_CASES: &[((i64, u32), i64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn ashrdi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __ashrdi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Ashrti3 {
+        a: i128,
+        b: u32,
+        c: i128,
+    }
+
+    impl TestCase for Ashrti3 {
+        fn name() -> &'static str {
+            "ashrti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i128(rng);
+            let b = (rng.gen::<u8>() % 128) as u32;
+            let c = a >> b;
+
+            Some(Ashrti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__ashrti3;
+
+static TEST_CASES: &[((i128, u32), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn ashrti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __ashrti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divmoddi4 {
+        a: i64,
+        b: i64,
+        c: i64,
+        rem: i64,
+    }
+
+    impl TestCase for Divmoddi4 {
+        fn name() -> &'static str {
+            "divmoddi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i64(rng);
+            let b = gen_i64(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+            let rem = a % b;
+
+            Some(Divmoddi4 { a, b, c, rem })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {rem})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                rem = self.rem
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__divmoddi4;
+
+static TEST_CASES: &[((i64, i64), (i64, i64))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divmoddi4() {
+    for &((a, b), (c, rem)) in TEST_CASES {
+        let mut rem_ = 0;
+        let c_ = __divmoddi4(a, b, &mut rem_);
+        assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divdi3 {
+        a: i64,
+        b: i64,
+        c: i64,
+    }
+
+    impl TestCase for Divdi3 {
+        fn name() -> &'static str {
+            "divdi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i64(rng);
+            let b = gen_i64(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+
+            Some(Divdi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__divdi3;
+
+static TEST_CASES: &[((i64, i64), i64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divdi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __divdi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divmodsi4 {
+        a: i32,
+        b: i32,
+        c: i32,
+        rem: i32,
+    }
+
+    impl TestCase for Divmodsi4 {
+        fn name() -> &'static str {
+            "divmodsi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i32(rng);
+            let b = gen_i32(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+            let rem = a % b;
+
+            Some(Divmodsi4 { a, b, c, rem })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {rem})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                rem = self.rem
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__divmodsi4;
+
+static TEST_CASES: &[((i32, i32), (i32, i32))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divmodsi4() {
+    for &((a, b), (c, rem)) in TEST_CASES {
+        let mut rem_ = 0;
+        let c_ = __divmodsi4(a, b, &mut rem_);
+        assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divsi3 {
+        a: i32,
+        b: i32,
+        c: i32,
+    }
+
+    impl TestCase for Divsi3 {
+        fn name() -> &'static str {
+            "divsi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i32(rng);
+            let b = gen_i32(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+
+            Some(Divsi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__divsi3;
+
+static TEST_CASES: &[((i32, i32), i32)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divsi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __divsi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divti3 {
+        a: i128,
+        b: i128,
+        c: i128,
+    }
+
+    impl TestCase for Divti3 {
+        fn name() -> &'static str {
+            "divti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i128(rng);
+            let b = gen_i128(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+
+            Some(Divti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__divti3;
+
+static TEST_CASES: &[((i128, i128), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __divti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixdfdi {
+        a: u64,  // f64
+        b: i64,
+    }
+
+    impl TestCase for Fixdfdi {
+        fn name() -> &'static str {
+            "fixdfdi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            i64(a).ok().map(|b| Fixdfdi { a: to_u64(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixdfdi;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64,), i64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixdfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixdfdi(mk_f64(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixdfsi {
+        a: u64,  // f64
+        b: i32,
+    }
+
+    impl TestCase for Fixdfsi {
+        fn name() -> &'static str {
+            "fixdfsi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            i32(a).ok().map(|b| Fixdfsi { a: to_u64(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixdfsi;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64,), i32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixdfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixdfsi(mk_f64(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixsfdi {
+        a: u32,  // f32
+        b: i64,
+    }
+
+    impl TestCase for Fixsfdi {
+        fn name() -> &'static str {
+            "fixsfdi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            i64(a).ok().map(|b| Fixsfdi { a: to_u32(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixsfdi;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), i64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixsfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixsfdi(mk_f32(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixsfsi {
+        a: u32,  // f32
+        b: i32,
+    }
+
+    impl TestCase for Fixsfsi {
+        fn name() -> &'static str {
+            "fixsfsi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            i32(a).ok().map(|b| Fixsfsi { a: to_u32(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixsfsi;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), i32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixsfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixsfsi(mk_f32(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixunsdfdi {
+        a: u64,  // f64
+        b: u64,
+    }
+
+    impl TestCase for Fixunsdfdi {
+        fn name() -> &'static str {
+            "fixunsdfdi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            u64(a).ok().map(|b| Fixunsdfdi { a: to_u64(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixunsdfdi;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixunsdfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixunsdfdi(mk_f64(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixunsdfsi {
+        a: u64,  // f64
+        b: u32,
+    }
+
+    impl TestCase for Fixunsdfsi {
+        fn name() -> &'static str {
+            "fixunsdfsi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            u32(a).ok().map(|b| Fixunsdfsi { a: to_u64(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixunsdfsi;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64,), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixunsdfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixunsdfsi(mk_f64(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixunssfdi {
+        a: u32,  // f32
+        b: u64,
+    }
+
+    impl TestCase for Fixunssfdi {
+        fn name() -> &'static str {
+            "fixunssfdi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            u64(a).ok().map(|b| Fixunssfdi { a: to_u32(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixunssfdi;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixunssfdi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixunssfdi(mk_f32(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Fixunssfsi {
+        a: u32,  // f32
+        b: u32,
+    }
+
+    impl TestCase for Fixunssfsi {
+        fn name() -> &'static str {
+            "fixunssfsi"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            u32(a).ok().map(|b| Fixunssfsi { a: to_u32(a), b })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__fixunssfsi;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn fixunssfsi() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __fixunssfsi(mk_f32(a));
+        assert_eq!(((a,), b), ((a,), b_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatdidf {
+        a: i64,
+        b: u64, // f64
+    }
+
+    impl TestCase for Floatdidf {
+        fn name() -> &'static str {
+            "floatdidf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i64(rng);
+            Some(
+                Floatdidf {
+                    a,
+                    b: to_u64(f64(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatdidf;
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((i64,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatdidf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatdidf(a);
+        assert_eq!(((a,), b), ((a,), to_u64(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatsidf {
+        a: i32,
+        b: u64, // f64
+    }
+
+    impl TestCase for Floatsidf {
+        fn name() -> &'static str {
+            "floatsidf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i32(rng);
+            Some(
+                Floatsidf {
+                    a,
+                    b: to_u64(f64(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatsidf;
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((i32,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatsidf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatsidf(a);
+        assert_eq!(((a,), b), ((a,), to_u64(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatsisf {
+        a: i32,
+        b: u32, // f32
+    }
+
+    impl TestCase for Floatsisf {
+        fn name() -> &'static str {
+            "floatsisf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i32(rng);
+            Some(
+                Floatsisf {
+                    a,
+                    b: to_u32(f32(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatsisf;
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((i32,), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatsisf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatsisf(a);
+        assert_eq!(((a,), b), ((a,), to_u32(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatundidf {
+        a: u64,
+        b: u64, // f64
+    }
+
+    impl TestCase for Floatundidf {
+        fn name() -> &'static str {
+            "floatundidf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            Some(
+                Floatundidf {
+                    a,
+                    b: to_u64(f64(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatundidf;
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatundidf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatundidf(a);
+        assert_eq!(((a,), b), ((a,), to_u64(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatunsidf {
+        a: u32,
+        b: u64, // f64
+    }
+
+    impl TestCase for Floatunsidf {
+        fn name() -> &'static str {
+            "floatunsidf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u32(rng);
+            Some(
+                Floatunsidf {
+                    a,
+                    b: to_u64(f64(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatunsidf;
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatunsidf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatunsidf(a);
+        assert_eq!(((a,), b), ((a,), to_u64(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Floatunsisf {
+        a: u32,
+        b: u32, // f32
+    }
+
+    impl TestCase for Floatunsisf {
+        fn name() -> &'static str {
+            "floatunsisf"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u32(rng);
+            Some(
+                Floatunsisf {
+                    a,
+                    b: to_u32(f32(a)),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::conv::__floatunsisf;
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32,), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn floatunsisf() {
+    for &((a,), b) in TEST_CASES {
+        let b_ = __floatunsisf(a);
+        assert_eq!(((a,), b), ((a,), to_u32(b_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Moddi3 {
+        a: i64,
+        b: i64,
+        c: i64,
+    }
+
+    impl TestCase for Moddi3 {
+        fn name() -> &'static str {
+            "moddi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i64(rng);
+            let b = gen_i64(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a % b;
+
+            Some(Moddi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__moddi3;
+
+static TEST_CASES: &[((i64, i64), i64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn moddi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __moddi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Modsi3 {
+        a: i32,
+        b: i32,
+        c: i32,
+    }
+
+    impl TestCase for Modsi3 {
+        fn name() -> &'static str {
+            "modsi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i32(rng);
+            let b = gen_i32(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a % b;
+
+            Some(Modsi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__modsi3;
+
+static TEST_CASES: &[((i32, i32), i32)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn modsi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __modsi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Modti3 {
+        a: i128,
+        b: i128,
+        c: i128,
+    }
+
+    impl TestCase for Modti3 {
+        fn name() -> &'static str {
+            "modti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i128(rng);
+            let b = gen_i128(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a % b;
+
+            Some(Modti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::sdiv::__modti3;
+
+static TEST_CASES: &[((i128, i128), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn modti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __modti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    struct Muldi3 {
+        a: u64,
+        b: u64,
+        c: u64,
+    }
+
+    impl TestCase for Muldi3 {
+        fn name() -> &'static str {
+            "muldi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = gen_u64(rng);
+            let c = a.wrapping_mul(b);
+
+            Some(Muldi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::mul::__muldi3;
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn muldi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __muldi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Mulodi4 {
+        a: i64,
+        b: i64,
+        c: i64,
+        overflow: u32,
+    }
+
+    impl TestCase for Mulodi4 {
+        fn name() -> &'static str {
+            "mulodi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+        {
+            let a = gen_i64(rng);
+            let b = gen_i64(rng);
+            let c = a.wrapping_mul(b);
+            let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 };
+
+            Some(Mulodi4 { a, b, c, overflow })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {overflow})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                overflow = self.overflow
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::mul::__mulodi4;
+
+static TEST_CASES: &[((i64, i64), (i64, i32))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn mulodi4() {
+    let mut overflow_ = 2;
+    for &((a, b), (c, overflow)) in TEST_CASES {
+        let c_ = __mulodi4(a, b, &mut overflow_);
+        assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Mulosi4 {
+        a: i32,
+        b: i32,
+        c: i32,
+        overflow: u32,
+    }
+
+    impl TestCase for Mulosi4 {
+        fn name() -> &'static str {
+            "mulosi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+        {
+            let a = gen_i32(rng);
+            let b = gen_i32(rng);
+            let c = a.wrapping_mul(b);
+            let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 };
+
+            Some(Mulosi4 { a, b, c, overflow })
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::mul::__mulosi4;
+
+static TEST_CASES: &[((i32, i32), (i32, i32))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn mulosi4() {
+    let mut overflow_ = 2;
+    for &((a, b), (c, overflow)) in TEST_CASES {
+        let c_ = __mulosi4(a, b, &mut overflow_);
+        assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_)));
+    }
+}
+"
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {overflow})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                overflow = self.overflow
+            )
+                    .unwrap();
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Muloti4 {
+        a: i128,
+        b: i128,
+        c: i128,
+        overflow: u32,
+    }
+
+    impl TestCase for Muloti4 {
+        fn name() -> &'static str {
+            "muloti4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+        {
+            let a = gen_i128(rng);
+            let b = gen_i128(rng);
+            let c = a.wrapping_mul(b);
+            let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 };
+
+            Some(Muloti4 { a, b, c, overflow })
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::mul::__muloti4;
+
+static TEST_CASES: &[((i128, i128), (i128, i32))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn muloti4() {
+    let mut overflow_ = 2;
+    for &((a, b), (c, overflow)) in TEST_CASES {
+        let c_ = __muloti4(a, b, &mut overflow_);
+        assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_)));
+    }
+}
+"
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {overflow})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                overflow = self.overflow
+            )
+                    .unwrap();
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Multi3 {
+        a: i128,
+        b: i128,
+        c: i128,
+    }
+
+    impl TestCase for Multi3 {
+        fn name() -> &'static str {
+            "multi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_i128(rng);
+            let b = gen_i128(rng);
+            let c = a.wrapping_mul(b);
+
+            Some(Multi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::mul::__multi3;
+
+static TEST_CASES: &[((i128, i128), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn multi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __multi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Powidf2 {
+        a: u64,  // f64
+        b: i32,
+        c: u64,  // f64
+    }
+
+    impl TestCase for Powidf2 {
+        fn name() -> &'static str {
+            "powidf2"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            let b = gen_i32(rng);
+            let c = a.powi(b);
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets
+            if a.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Powidf2 {
+                    a: to_u64(a),
+                    b,
+                    c: to_u64(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::pow::__powidf2;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64, i32), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn powidf2() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __powidf2(mk_f64(a), b);
+        assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Powisf2 {
+        a: u32,  // f32
+        b: i32,
+        c: u32,  // f32
+    }
+
+    impl TestCase for Powisf2 {
+        fn name() -> &'static str {
+            "powisf2"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            let b = gen_i32(rng);
+            let c = a.powi(b);
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets
+            if a.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Powisf2 {
+                    a: to_u32(a),
+                    b,
+                    c: to_u32(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::pow::__powisf2;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32, i32), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn powisf2() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __powisf2(mk_f32(a), b);
+        assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Lshrdi3 {
+        a: u64,
+        b: u32,
+        c: u64,
+    }
+
+    impl TestCase for Lshrdi3 {
+        fn name() -> &'static str {
+            "lshrdi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = (rng.gen::<u8>() % 64) as u32;
+            let c = a >> b;
+
+            Some(Lshrdi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__lshrdi3;
+
+static TEST_CASES: &[((u64, u32), u64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn lshrdi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __lshrdi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Lshrti3 {
+        a: u128,
+        b: u32,
+        c: u128,
+    }
+
+    impl TestCase for Lshrti3 {
+        fn name() -> &'static str {
+            "lshrti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = (rng.gen::<u8>() % 128) as u32;
+            let c = a >> b;
+
+            Some(Lshrti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::shift::__lshrti3;
+
+static TEST_CASES: &[((u128, u32), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn lshrti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __lshrti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Subdf3 {
+        a: u64,  // f64
+        b: u64,  // f64
+        c: u64,  // f64
+    }
+
+    impl TestCase for Subdf3 {
+        fn name() -> &'static str {
+            "subdf3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f64(rng);
+            let b = gen_f64(rng);
+            let c = a - b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Subdf3 {
+                    a: to_u64(a),
+                    b: to_u64(b),
+                    c: to_u64(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::sub::__subdf3;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn subdf3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __subdf3(mk_f64(a), mk_f64(b));
+        assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Subsf3 {
+        a: u32,  // f32
+        b: u32,  // f32
+        c: u32,  // f32
+    }
+
+    impl TestCase for Subsf3 {
+        fn name() -> &'static str {
+            "subsf3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_f32(rng);
+            let b = gen_f32(rng);
+            let c = a - b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Subsf3 {
+                    a: to_u32(a),
+                    b: to_u32(b),
+                    c: to_u32(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::sub::__subsf3;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn subsf3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __subsf3(mk_f32(a), mk_f32(b));
+        assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivdi3 {
+        a: u64,
+        b: u64,
+        c: u64,
+    }
+
+    impl TestCase for Udivdi3 {
+        fn name() -> &'static str {
+            "udivdi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = gen_u64(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+
+            Some(Udivdi3 { a, b, c })
+        }
 
-#[cfg(feature = "c")]
-use std::collections::BTreeMap;
-use std::io::Write;
-#[cfg(feature = "c")]
-use std::path::Path;
-use std::{env, io, process};
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
 
-use rustc_cfg::Cfg;
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivdi3;
 
-#[cfg(feature = "c")]
-struct Sources {
-    // SYMBOL -> PATH TO SOURCE
-    map: BTreeMap<&'static str, &'static str>,
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivdi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __udivdi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
 }
+"
+        }
+    }
 
-#[cfg(feature = "c")]
-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);
-                }
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivmoddi4 {
+        a: u64,
+        b: u64,
+        c: u64,
+        rem: u64,
+    }
+
+    impl TestCase for Udivmoddi4 {
+        fn name() -> &'static str {
+            "udivmoddi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = gen_u64(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a / b;
+            let rem = a % b;
+
+            Some(Udivmoddi4 { a, b, c, rem })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {rem})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                rem = self.rem
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivmoddi4;
+
+static TEST_CASES: &[((u64, u64), (u64, u64))] = &[
+"
         }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivmoddi4() {
+    for &((a, b), (c, rem)) in TEST_CASES {
+        let mut rem_ = 0;
+        let c_ = __udivmoddi4(a, b, Some(&mut rem_));
+        assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivmodsi4 {
+        a: u32,
+        b: u32,
+        c: u32,
+        rem: u32,
     }
 
-    fn remove(&mut self, symbols: &[&str]) {
-        for symbol in symbols {
-            self.map.remove(*symbol).unwrap();
+    impl TestCase for Udivmodsi4 {
+        fn name() -> &'static str {
+            "udivmodsi4"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u32(rng);
+            let b = gen_u32(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+            let rem = a % b;
+
+            Some(Udivmodsi4 { a, b, c, rem })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {rem})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                rem = self.rem
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivmodsi4;
+
+static TEST_CASES: &[((u32, u32), (u32, u32))] = &[
+"
         }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivmodsi4() {
+    for &((a, b), (c, rem)) in TEST_CASES {
+        let mut rem_ = 0;
+        let c_ = __udivmodsi4(a, b, Some(&mut rem_));
+        assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_)));
     }
 }
+"
+        }
+    }
 
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivmodti4 {
+        a: u128,
+        b: u128,
+        c: u128,
+        rem: u128,
+    }
 
-    let target = env::var("TARGET").unwrap();
+    impl TestCase for Udivmodti4 {
+        fn name() -> &'static str {
+            "udivmodti4"
+        }
 
-    // Emscripten's runtime includes all the builtins
-    if target.contains("emscripten") {
-        return;
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            if b == 0 {
+                return None;
+            }
+            let c = a / b;
+            let rem = a % b;
+
+            Some(Udivmodti4 { a, b, c, rem })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {rem})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                rem = self.rem
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivmodti4;
+
+static TEST_CASES: &[((u128, u128), (u128, u128))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivmodti4() {
+    for &((a, b), (c, rem)) in TEST_CASES {
+        let mut rem_ = 0;
+        let c_ = __udivmodti4(a, b, Some(&mut rem_));
+        assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_)));
+    }
+}
+"
+        }
     }
 
-    let Cfg { ref target_arch, ref target_os, ref target_env, ref target_vendor, .. } =
-        Cfg::new(&target).unwrap_or_else(|e| {
-            writeln!(io::stderr(), "{}", e).ok();
-            process::exit(1)
-        });
-    // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
-    // target triple. This is usually correct for our built-in targets but can break in presence of
-    // custom targets, which can have arbitrary names.
-    let llvm_target = target.split('-').collect::<Vec<_>>();
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivsi3 {
+        a: u32,
+        b: u32,
+        c: u32,
+    }
 
-    // Build missing intrinsics from compiler-rt C source code
-    match () {
-        #[cfg(feature = "c")]
-        () => {
-            let target_vendor = target_vendor.as_ref().unwrap();
-            let cfg = &mut gcc::Config::new();
-
-            if target_env == "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");
-                cfg.flag("-fomit-frame-pointer");
-                cfg.flag("-ffreestanding");
-                cfg.define("VISIBILITY_HIDDEN", None);
-            }
-
-            // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to
-            // target to make sure that the assembly implementations really work for the target. If the
-            // implementation is not valid for the arch, then gcc will error when compiling it.
-            if llvm_target[0].starts_with("thumb") {
-                cfg.flag("-mthumb");
-
-                if llvm_target.last() == Some(&"eabihf") {
-                    cfg.flag("-mfloat-abi=hard");
-                }
+    impl TestCase for Udivsi3 {
+        fn name() -> &'static str {
+            "udivsi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u32(rng);
+            let b = gen_u32(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a / b;
 
-            if llvm_target[0] == "thumbv6m" {
-                cfg.flag("-march=armv6-m");
-            }
-
-            if llvm_target[0] == "thumbv7m" {
-                cfg.flag("-march=armv7-m");
-            }
-
-            if llvm_target[0] == "thumbv7em" {
-                cfg.flag("-march=armv7e-m");
-            }
-
-            let mut sources = Sources::new();
-            sources.extend(&["absvdi2.c",
-                            "absvsi2.c",
-                            "addvdi3.c",
-                            "addvsi3.c",
-                            "apple_versioning.c",
-                            "clzdi2.c",
-                            "clzsi2.c",
-                            "cmpdi2.c",
-                            "comparedf2.c",
-                            "comparesf2.c",
-                            "ctzdi2.c",
-                            "ctzsi2.c",
-                            "divdc3.c",
-                            "divdf3.c",
-                            "divsc3.c",
-                            "divsf3.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",
-                            "muldc3.c",
-                            "muldf3.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",
-                            "powixf2.c",
-                            "subvdi3.c",
-                            "subvsi3.c",
-                            "truncdfhf2.c",
-                            "truncdfsf2.c",
-                            "truncsfhf2.c",
-                            "ucmpdi2.c"]);
-
-            if target_os != "ios" {
-                sources.extend(&["absvti2.c",
-                                "addvti3.c",
-                                "clzti2.c",
-                                "cmpti2.c",
-                                "ctzti2.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",
-                                "mulvti3.c",
-                                "negti2.c",
-                                "negvti2.c",
-                                "parityti2.c",
-                                "popcountti2.c",
-                                "subvti3.c",
-                                "ucmpti2.c"]);
-            }
-
-            if target_vendor == "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_env == "msvc" {
-                if target_arch == "x86_64" {
-                    sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
-                }
-            } else {
-                if target_os != "freebsd" && target_os != "netbsd" {
-                    sources.extend(&["gcc_personality_v0.c"]);
-                }
+            Some(Udivsi3 { a, b, c })
+        }
 
-                if target_arch == "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"]);
-                }
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
 
-                if target_arch == "x86" {
-                    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"]);
-                }
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivsi3;
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivsi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __udivsi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Udivti3 {
+        a: u128,
+        b: u128,
+        c: u128,
+    }
+
+    impl TestCase for Udivti3 {
+        fn name() -> &'static str {
+            "udivti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a / b;
 
-            if target_arch == "arm" && target_os != "ios" {
-                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/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 llvm_target[0] == "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 llvm_target.last().unwrap().ends_with("eabihf") {
-                if !llvm_target[0].starts_with("thumbv7em") {
-                    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/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"]);
-                }
+            Some(Udivti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__udivti3;
+
+static TEST_CASES: &[((u128, u128), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn udivti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __udivti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Umoddi3 {
+        a: u64,
+        b: u64,
+        c: u64,
+    }
 
-                sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]);
+    impl TestCase for Umoddi3 {
+        fn name() -> &'static str {
+            "umoddi3"
+        }
 
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u64(rng);
+            let b = gen_u64(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a % b;
+
+            Some(Umoddi3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__umoddi3;
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn umoddi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __umoddi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Umodsi3 {
+        a: u32,
+        b: u32,
+        c: u32,
+    }
 
-            if target_arch == "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"]);
+    impl TestCase for Umodsi3 {
+        fn name() -> &'static str {
+            "umodsi3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u32(rng);
+            let b = gen_u32(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a % b;
+
+            Some(Umodsi3 { a, b, c })
+        }
 
-            // Remove the assembly implementations that won't compile for the target
-            if llvm_target[0] == "thumbv6m" {
-                sources.remove(&["aeabi_cdcmp",
-                                "aeabi_cfcmp",
-                                "aeabi_dcmp",
-                                "aeabi_fcmp",
-                                "clzdi2",
-                                "clzsi2",
-                                "comparesf2",
-                                "divmodsi4",
-                                "divsi3",
-                                "modsi3",
-                                "switch16",
-                                "switch32",
-                                "switch8",
-                                "switchu8",
-                                "udivmodsi4",
-                                "udivsi3",
-                                "umodsi3"]);
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__umodsi3;
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn umodsi3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __umodsi3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Umodti3 {
+        a: u128,
+        b: u128,
+        c: u128,
+    }
 
-                // But use some generic implementations where possible
-                sources.extend(&["clzdi2.c", "clzsi2.c"])
+    impl TestCase for Umodti3 {
+        fn name() -> &'static str {
+            "umodti3"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            if b == 0 {
+                return None;
             }
+            let c = a % b;
+
+            Some(Umodti3 { a, b, c })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::udiv::__umodti3;
+
+static TEST_CASES: &[((u128, u128), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn umodti3() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __umodti3(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    trait TestCase {
+        /// Name of the intrinsic to test
+        fn name() -> &'static str;
+        /// Generates a valid test case
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized;
+        /// Stringifies a test case
+        fn to_string(&self, buffer: &mut String);
+        /// Prologue of the test file
+        fn prologue() -> &'static str;
+        /// Epilogue of the test file
+        fn epilogue() -> &'static str;
+    }
+
+    const PROLOGUE: &'static str = r#"
+extern crate compiler_builtins;
+
+// test runner
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+extern crate utest_cortex_m_qemu;
+
+// overrides `panic!`
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+#[macro_use]
+extern crate utest_macros;
 
-            if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" {
-                sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]);
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+macro_rules! panic {
+    ($($tt:tt)*) => {
+        upanic!($($tt)*);
+    };
+}
+"#;
+
+    macro_rules! gen_int {
+        ($name:ident, $ity:ident, $hty:ident) => {
+            fn $name<R>(rng: &mut R) -> $ity
+                where
+                R: Rng,
+            {
+                let mut mk = || if rng.gen_weighted_bool(10) {
+                    *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap()
+                } else {
+                    rng.gen::<$hty>()
+                };
+                unsafe { mem::transmute([mk(), mk()]) }
             }
 
-            let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() {
-                Path::new("../../libcompiler_builtins")
-            } else {
-                Path::new(".")
-            };
+        }
+    }
+
+    gen_int!(gen_i32, i32, i16);
+    gen_int!(gen_i64, i64, i32);
+    gen_int!(gen_i128, i128, i64);
+
+    macro_rules! gen_float {
+        ($name:ident,
+         $fty:ident,
+         $uty:ident,
+         $bits:expr,
+         $significand_bits:expr) => {
+            pub fn $name<R>(rng: &mut R) -> $fty
+            where
+                R: Rng,
+            {
+                const BITS: u8 = $bits;
+                const SIGNIFICAND_BITS: u8 = $significand_bits;
+
+                const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1;
+                const SIGN_MASK: $uty = (1 << (BITS - 1));
+                const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK);
+
+                fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty {
+                    unsafe {
+                        mem::transmute(((sign as $uty) << (BITS - 1)) |
+                                       ((exponent & EXPONENT_MASK) <<
+                                        SIGNIFICAND_BITS) |
+                                       (significand & SIGNIFICAND_MASK))
+                    }
+                }
 
-            let src_dir = root.join("compiler-rt/compiler-rt-cdylib/compiler-rt/lib/builtins");
-            for src in sources.map.values() {
-                let src = src_dir.join(src);
-                cfg.file(&src);
-                println!("cargo:rerun-if-changed={}", src.display());
+                if rng.gen_weighted_bool(10) {
+                    // Special values
+                    *rng.choose(&[-0.0,
+                                  0.0,
+                                  ::std::$fty::NAN,
+                                  ::std::$fty::INFINITY,
+                                  -::std::$fty::INFINITY])
+                        .unwrap()
+                } else if rng.gen_weighted_bool(10) {
+                    // NaN patterns
+                    mk_f32(rng.gen(), rng.gen(), 0)
+                } else if rng.gen() {
+                    // Denormalized
+                    mk_f32(rng.gen(), 0, rng.gen())
+                } else {
+                    // Random anything
+                    mk_f32(rng.gen(), rng.gen(), rng.gen())
+                }
             }
+        }
+    }
+
+    gen_float!(gen_f32, f32, u32, 32, 23);
+    gen_float!(gen_f64, f64, u64, 64, 52);
+
+    pub fn gen_u128<R>(rng: &mut R) -> u128
+    where
+        R: Rng,
+    {
+        gen_i128(rng) as u128
+    }
+
+    pub fn gen_u32<R>(rng: &mut R) -> u32
+    where
+        R: Rng,
+    {
+        gen_i32(rng) as u32
+    }
+
+    fn gen_u64<R>(rng: &mut R) -> u64
+    where
+        R: Rng,
+    {
+        gen_i64(rng) as u64
+    }
+
+    pub fn to_u32(x: f32) -> u32 {
+        unsafe { mem::transmute(x) }
+    }
+
+    pub fn to_u64(x: f64) -> u64 {
+        unsafe { mem::transmute(x) }
+    }
 
-            cfg.compile("libcompiler-rt.a");
+    fn mk_tests<T, R>(mut n: usize, rng: &mut R) -> String
+    where
+        T: Eq + Hash + TestCase,
+        R: Rng,
+    {
+        let mut buffer = PROLOGUE.to_owned();
+        buffer.push_str(T::prologue());
+        let mut cases = HashSet::new();
+        while n != 0 {
+            if let Some(case) = T::generate(rng) {
+                if cases.contains(&case) {
+                    continue;
+                }
+                case.to_string(&mut buffer);
+                n -= 1;
+                cases.insert(case);
+            }
         }
-        #[cfg(not(feature = "c"))]
-        () => {}
+        buffer.push_str(T::epilogue());
+        buffer
     }
 
-    // To filter away some flaky test (see src/float/add.rs for details)
-    if llvm_target[0].starts_with("arm") &&
-       llvm_target.last().unwrap().contains("gnueabi") {
-        println!("cargo:rustc-cfg=arm_linux")
+    fn mk_file<T>()
+    where
+        T: Eq + Hash + TestCase,
+    {
+        use std::io::Write;
+
+        let rng = &mut rand::thread_rng();
+        let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+        let out_file = out_dir.join(format!("{}.rs", T::name()));
+        let contents = mk_tests::<T, _>(NTESTS, rng);
+
+        File::create(out_file)
+            .unwrap()
+            .write_all(contents.as_bytes())
+            .unwrap();
     }
+}
 
-    // To compile intrinsics.rs for thumb targets, where there is no libc
-    if llvm_target[0].starts_with("thumb") {
-        println!("cargo:rustc-cfg=thumb")
+#[cfg(feature = "c")]
+mod c {
+    extern crate gcc;
+
+    use std::collections::BTreeMap;
+    use std::env;
+    use std::path::Path;
+
+    struct Sources {
+        // SYMBOL -> PATH TO SOURCE
+        map: BTreeMap<&'static str, &'static str>,
     }
 
-    // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full
-    // THUMBv2 support. We have to cfg our code accordingly.
-    if llvm_target[0] == "thumbv6m" {
-        println!("cargo:rustc-cfg=thumbv6m")
+    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 remove(&mut self, symbols: &[&str]) {
+            for symbol in symbols {
+                self.map.remove(*symbol).unwrap();
+            }
+        }
+    }
+
+    /// Compile intrinsics from the compiler-rt C source code
+    pub fn compile(llvm_target: &[&str]) {
+        let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
+        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
+        let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
+        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
+
+        let cfg = &mut gcc::Config::new();
+
+        if target_env == "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");
+            cfg.flag("-fomit-frame-pointer");
+            cfg.flag("-ffreestanding");
+            cfg.define("VISIBILITY_HIDDEN", None);
+        }
+
+        // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going
+        // to target to make sure that the assembly implementations really work for the target. If
+        // the implementation is not valid for the arch, then gcc will error when compiling it.
+        if llvm_target[0].starts_with("thumb") {
+            cfg.flag("-mthumb");
+
+            if llvm_target.last() == Some(&"eabihf") {
+                cfg.flag("-mfloat-abi=hard");
+            }
+        }
+
+        if llvm_target[0] == "thumbv6m" {
+            cfg.flag("-march=armv6-m");
+        }
+
+        if llvm_target[0] == "thumbv7m" {
+            cfg.flag("-march=armv7-m");
+        }
+
+        if llvm_target[0] == "thumbv7em" {
+            cfg.flag("-march=armv7e-m");
+        }
+
+        let mut sources = Sources::new();
+        sources.extend(
+            &[
+                "absvdi2.c",
+                "absvsi2.c",
+                "addvdi3.c",
+                "addvsi3.c",
+                "apple_versioning.c",
+                "clzdi2.c",
+                "clzsi2.c",
+                "cmpdi2.c",
+                "comparedf2.c",
+                "comparesf2.c",
+                "ctzdi2.c",
+                "ctzsi2.c",
+                "divdc3.c",
+                "divdf3.c",
+                "divsc3.c",
+                "divsf3.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",
+                "muldc3.c",
+                "muldf3.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",
+                "powixf2.c",
+                "subvdi3.c",
+                "subvsi3.c",
+                "truncdfhf2.c",
+                "truncdfsf2.c",
+                "truncsfhf2.c",
+                "ucmpdi2.c",
+            ],
+        );
+
+        if target_os != "ios" {
+            sources.extend(
+                &[
+                    "absvti2.c",
+                    "addvti3.c",
+                    "clzti2.c",
+                    "cmpti2.c",
+                    "ctzti2.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",
+                    "mulvti3.c",
+                    "negti2.c",
+                    "negvti2.c",
+                    "parityti2.c",
+                    "popcountti2.c",
+                    "subvti3.c",
+                    "ucmpti2.c",
+                ],
+            );
+        }
+
+        if target_vendor == "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_env == "msvc" {
+            if target_arch == "x86_64" {
+                sources.extend(
+                    &[
+                        "x86_64/floatdidf.c",
+                        "x86_64/floatdisf.c",
+                        "x86_64/floatdixf.c",
+                    ],
+                );
+            }
+        } else {
+            if target_os != "freebsd" && target_os != "netbsd" {
+                sources.extend(&["gcc_personality_v0.c"]);
+            }
+
+            if target_arch == "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_arch == "x86" {
+                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_arch == "arm" && target_os != "ios" {
+            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/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 llvm_target[0] == "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 llvm_target.last().unwrap().ends_with("eabihf") {
+            if !llvm_target[0].starts_with("thumbv7em") {
+                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/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",
+                    ],
+                );
+            }
+
+            sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]);
+
+        }
+
+        if target_arch == "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",
+                ],
+            );
+        }
+
+        // Remove the assembly implementations that won't compile for the target
+        if llvm_target[0] == "thumbv6m" {
+            sources.remove(
+                &[
+                    "aeabi_cdcmp",
+                    "aeabi_cfcmp",
+                    "aeabi_dcmp",
+                    "aeabi_fcmp",
+                    "clzdi2",
+                    "clzsi2",
+                    "comparesf2",
+                    "divmodsi4",
+                    "divsi3",
+                    "modsi3",
+                    "switch16",
+                    "switch32",
+                    "switch8",
+                    "switchu8",
+                    "udivmodsi4",
+                    "udivsi3",
+                    "umodsi3",
+                ],
+            );
+
+            // But use some generic implementations where possible
+            sources.extend(&["clzdi2.c", "clzsi2.c"])
+        }
+
+        if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" {
+            sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]);
+        }
+
+        let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() {
+            Path::new("../../libcompiler_builtins")
+        } else {
+            Path::new(".")
+        };
+
+        let src_dir = root.join("compiler-rt/lib/builtins");
+        for src in sources.map.values() {
+            let src = src_dir.join(src);
+            cfg.file(&src);
+            println!("cargo:rerun-if-changed={}", src.display());
+        }
+
+        cfg.compile("libcompiler-rt.a");
     }
 }

+ 4 - 4
ci/docker/thumbv7m-none-eabi/Dockerfile → ci/docker/thumbv6m-linux-eabi/Dockerfile

@@ -1,9 +1,9 @@
 FROM ubuntu:16.04
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
-    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
+    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static
 RUN curl -LSfs https://japaric.github.io/trust/install.sh | \
     sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin
-ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \
-    CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \
-    CC_thumbv7m_none_eabi=arm-none-eabi-gcc \
+ENV AR_thumbv6m_linux_eabi=arm-none-eabi-ar \
+    CARGO_TARGET_THUMBV6M_LINUX_EABI_LINKER=arm-none-eabi-gcc \
+    CC_thumbv6m_linux_eabi=arm-none-eabi-gcc \

+ 4 - 4
ci/docker/thumbv7em-none-eabi/Dockerfile → ci/docker/thumbv7em-linux-eabi/Dockerfile

@@ -1,9 +1,9 @@
 FROM ubuntu:16.04
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
-    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
+    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static
 RUN curl -LSfs https://japaric.github.io/trust/install.sh | \
     sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin
-ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \
-    CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \
-    CC_thumbv7em_none_eabi=arm-none-eabi-gcc \
+ENV AR_thumbv7em_linux_eabi=arm-none-eabi-ar \
+    CARGO_TARGET_THUMBV7EM_LINUX_EABI_LINKER=arm-none-eabi-gcc \
+    CC_thumbv7em_linux_eabi=arm-none-eabi-gcc \

+ 4 - 4
ci/docker/thumbv7em-none-eabihf/Dockerfile → ci/docker/thumbv7em-linux-eabihf/Dockerfile

@@ -1,9 +1,9 @@
 FROM ubuntu:16.04
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
-    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
+    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static
 RUN curl -LSfs https://japaric.github.io/trust/install.sh | \
     sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin
-ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \
-    CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \
-    CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \
+ENV AR_thumbv7em_linux_eabihf=arm-none-eabi-ar \
+    CARGO_TARGET_THUMBV7EM_LINUX_EABIHF_LINKER=arm-none-eabi-gcc \
+    CC_thumbv7em_linux_eabihf=arm-none-eabi-gcc \

+ 4 - 4
ci/docker/thumbv6m-none-eabi/Dockerfile → ci/docker/thumbv7m-linux-eabi/Dockerfile

@@ -1,9 +1,9 @@
 FROM ubuntu:16.04
 RUN apt-get update && \
     apt-get install -y --no-install-recommends \
-    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
+    ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev qemu-user-static
 RUN curl -LSfs https://japaric.github.io/trust/install.sh | \
     sh -s -- --git japaric/xargo --tag v0.3.1 --target x86_64-unknown-linux-gnu --to /usr/bin
-ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \
-    CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \
-    CC_thumbv6m_none_eabi=arm-none-eabi-gcc \
+ENV AR_thumbv7m_linux_eabi=arm-none-eabi-ar \
+    CARGO_TARGET_THUMBV7M_LINUX_EABI_LINKER=arm-none-eabi-gcc \
+    CC_thumbv7m_linux_eabi=arm-none-eabi-gcc \

+ 30 - 4
ci/run.sh

@@ -3,12 +3,38 @@ set -ex
 # Test our implementation
 case $1 in
     thumb*)
-        xargo build --target $1
-        xargo build --target $1 --release
+        for t in $(ls tests); do
+            t=${t%.rs}
+
+            # TODO(#154) enable these tests when aeabi_*mul are implemented
+            case $t in
+                powi*f2)
+                    continue
+                    ;;
+            esac
+
+            # FIXME(#150) debug assertion in divmoddi4
+            case $1 in
+                thumbv6m-*)
+                    case $t in
+                        divdi3 | divmoddi4 | moddi3 | modsi3 | udivmoddi4 | udivmodsi4 | umoddi3 | \
+                            umodsi3)
+                            continue
+                            ;;
+                    esac
+                ;;
+            esac
+
+            xargo test --test $t --target $1 --features 'mem gen-tests' --no-run
+            qemu-arm-static target/${1}/debug/$t-*
+
+            xargo test --test $t --target $1 --features 'mem gen-tests' --no-run --release
+            qemu-arm-static target/${1}/release/$t-*
+        done
         ;;
     *)
-        cargo test --no-default-features --target $1
-        cargo test --no-default-features --target $1 --release
+        cargo test --no-default-features --features gen-tests --target $1
+        cargo test --no-default-features --features gen-tests --target $1 --release
         ;;
 esac
 

+ 0 - 0
compiler-rt/compiler-rt-cdylib/compiler-rt → compiler-rt


+ 0 - 8
compiler-rt/Cargo.toml

@@ -1,8 +0,0 @@
-[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 - 12
compiler-rt/compiler-rt-cdylib/Cargo.toml

@@ -1,12 +0,0 @@
-[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.36"
-

+ 0 - 104
compiler-rt/compiler-rt-cdylib/build.rs

@@ -1,104 +0,0 @@
-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",
-        "powidf2.c",
-        "powisf2.c",
-        "subdf3.c",
-        "subsf3.c",
-        "floatsisf.c",
-        "floatsidf.c",
-        "floatdidf.c",
-        "floatunsisf.c",
-        "floatunsidf.c",
-        "floatundidf.c",
-        "fixsfsi.c",
-        "fixsfdi.c",
-        "fixdfsi.c",
-        "fixdfdi.c",
-        "fixunssfsi.c",
-        "fixunssfdi.c",
-        "fixunsdfsi.c",
-        "fixunsdfdi.c",
-        // 128 bit integers
-        "lshrti3.c",
-        "modti3.c",
-        "muloti4.c",
-        "multi3.c",
-        "udivmodti4.c",
-        "udivti3.c",
-        "umodti3.c",
-        "ashlti3.c",
-        "ashrti3.c",
-        "divti3.c",
-    ]);
-
-    let builtins_dir = Path::new("compiler-rt/lib/builtins");
-    for src in sources.files.iter() {
-        cfg.file(builtins_dir.join(src));
-    }
-
-    cfg.compile("libcompiler-rt.a");
-
-    println!("cargo:rerun-if-changed=build.rs");
-
-    for source in sources.files.iter() {
-        println!("cargo:rerun-if-changed={}", builtins_dir.join(source).display());
-    }
-}

+ 0 - 126
compiler-rt/compiler-rt-cdylib/src/lib.rs

@@ -1,126 +0,0 @@
-#![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();
-    fn __powisf2();
-    fn __powidf2();
-    fn __subsf3();
-    fn __subdf3();
-    fn __floatsisf();
-    fn __floatsidf();
-    fn __floatdidf();
-    fn __floatunsisf();
-    fn __floatunsidf();
-    fn __floatundidf();
-    fn __fixsfsi();
-    fn __fixsfdi();
-    fn __fixdfsi();
-    fn __fixdfdi();
-    fn __fixunssfsi();
-    fn __fixunssfdi();
-    fn __fixunsdfsi();
-    fn __fixunsdfdi();
-}
-
-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);
-declare!(___powisf2, __powisf2);
-declare!(___powidf2, __powidf2);
-declare!(___subsf3, __subsf3);
-declare!(___subdf3, __subdf3);
-declare!(___floatsisf, __floatsisf);
-declare!(___floatsidf, __floatsidf);
-declare!(___floatdidf, __floatdidf);
-declare!(___floatunsisf, __floatunsisf);
-declare!(___floatunsidf, __floatunsidf);
-declare!(___floatundidf, __floatundidf);
-declare!(___fixsfsi, __fixsfsi);
-declare!(___fixsfdi, __fixsfdi);
-declare!(___fixdfsi, __fixdfsi);
-declare!(___fixdfdi, __fixdfdi);
-declare!(___fixunssfsi, __fixunssfsi);
-declare!(___fixunssfdi, __fixunssfdi);
-declare!(___fixunsdfsi, __fixunsdfsi);
-declare!(___fixunsdfdi, __fixunsdfdi);
-
-#[cfg(all(not(windows),
-          not(target_arch = "mips64"),
-          not(target_arch = "mips64el"),
-          target_pointer_width="64"))]
-pub mod int_128 {
-    extern {
-        fn __lshrti3();
-        fn __modti3();
-        fn __muloti4();
-        fn __multi3();
-        fn __udivmodti4();
-        fn __udivti3();
-        fn __umodti3();
-        fn __ashlti3();
-        fn __ashrti3();
-        fn __divti3();
-    }
-
-    declare!(___lshrti3, __lshrti3);
-    declare!(___modti3, __modti3);
-    declare!(___muloti4, __muloti4);
-    declare!(___multi3, __multi3);
-    declare!(___udivmodti4, __udivmodti4);
-    declare!(___udivti3, __udivti3);
-    declare!(___umodti3, __umodti3);
-    declare!(___ashlti3, __ashlti3);
-    declare!(___ashrti3, __ashrti3);
-    declare!(___divti3, __divti3);
-}
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
-#[lang = "panic_fmt"]
-fn panic_fmt() {}

+ 0 - 35
compiler-rt/src/lib.rs

@@ -1,35 +0,0 @@
-#![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()
-    }
-}

+ 0 - 7
gcc_s/Cargo.toml

@@ -1,7 +0,0 @@
-[package]
-authors = ["Jorge Aparicio <japaricious@gmail.com>"]
-name = "gcc_s"
-version = "0.1.0"
-
-[dependencies]
-libloading = "0.3.0"

+ 0 - 39
gcc_s/src/lib.rs

@@ -1,39 +0,0 @@
-#![feature(drop_types_in_const)]
-
-extern crate libloading;
-
-use std::sync::{Once, ONCE_INIT};
-
-use libloading::Library;
-
-static mut GCC_S: Option<Library> = None;
-
-#[cfg(not(windows))]
-fn gcc_s() -> &'static Library {
-    #[cfg(not(target_os = "macos"))]
-    const LIBGCC_S: &'static str = "libgcc_s.so.1";
-
-    #[cfg(target_os = "macos")]
-    const LIBGCC_S: &'static str = "libgcc_s.1.dylib";
-
-    unsafe {
-        static INIT: Once = ONCE_INIT;
-
-        INIT.call_once(|| {
-            GCC_S = Some(Library::new(LIBGCC_S).unwrap());
-        });
-        GCC_S.as_ref().unwrap()
-    }
-}
-
-#[cfg(windows)]
-pub fn get(_sym: &str) -> Option<usize> {
-    None
-}
-
-#[cfg(not(windows))]
-pub fn get(sym: &str) -> Option<usize> {
-    unsafe {
-        gcc_s().get(sym.as_bytes()).ok().map(|s| *s)
-    }
-}

+ 0 - 81
src/arm.rs

@@ -180,84 +180,3 @@ pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
 pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
     memset(dest, 0, n);
 }
-
-
-#[cfg(test)]
-mod tests {
-    use quickcheck::TestResult;
-    use qc::{U32, U64};
-
-    quickcheck!{
-        fn uldivmod(n: U64, d: U64) -> TestResult {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                TestResult::discard()
-            } else {
-                let q: u64;
-                let r: u64;
-                unsafe {
-                    // The inline asm is a bit tricky here, LLVM will allocate
-                    // both r0 and r1 when we specify a 64-bit value for {r0}.
-                    asm!("bl __aeabi_uldivmod"
-                         : "={r0}" (q), "={r2}" (r)
-                         : "{r0}" (n), "{r2}" (d)
-                         : "r12", "lr", "flags");
-                }
-                TestResult::from_bool(q == n / d && r == n % d)
-            }
-        }
-
-        fn uidivmod(n: U32, d: U32) -> TestResult {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                TestResult::discard()
-            } else {
-                let q: u32;
-                let r: u32;
-                unsafe {
-                    asm!("bl __aeabi_uidivmod"
-                         : "={r0}" (q), "={r1}" (r)
-                         : "{r0}" (n), "{r1}" (d)
-                         : "r2", "r3", "r12", "lr", "flags");
-                }
-                TestResult::from_bool(q == n / d && r == n % d)
-            }
-        }
-
-        fn ldivmod(n: U64, d: U64) -> TestResult {
-            let (n, d) = (n.0 as i64, d.0 as i64);
-            if d == 0 {
-                TestResult::discard()
-            } else {
-                let q: i64;
-                let r: i64;
-                unsafe {
-                    // The inline asm is a bit tricky here, LLVM will allocate
-                    // both r0 and r1 when we specify a 64-bit value for {r0}.
-                    asm!("bl __aeabi_ldivmod"
-                         : "={r0}" (q), "={r2}" (r)
-                         : "{r0}" (n), "{r2}" (d)
-                         : "r12", "lr", "flags");
-                }
-                TestResult::from_bool(q == n / d && r == n % d)
-            }
-        }
-
-        fn idivmod(n: U32, d: U32) -> TestResult {
-            let (n, d) = (n.0 as i32, d.0 as i32);
-            if d == 0 || (n == i32::min_value() && d == -1) {
-                TestResult::discard()
-            } else {
-                let q: i32;
-                let r: i32;
-                unsafe {
-                    asm!("bl __aeabi_idivmod"
-                         : "={r0}" (q), "={r1}" (r)
-                         : "{r0}" (n), "{r1}" (d)
-                         : "r2", "r3", "r12", "lr", "flags");
-                }
-                TestResult::from_bool(q == n / d && r == n % d)
-            }
-        }
-    }
-}

+ 0 - 25
src/float/add.rs

@@ -192,28 +192,3 @@ add!("aapcs", __adddf3: f64);
 
 #[cfg(not(target_arch = "arm"))]
 add!("C", __adddf3: f64);
-
-// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't
-// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
-// just avoid testing against them on those targets. Do note that our implementation gives the
-// correct answer; gcc_s and compiler-rt are incorrect in this case.
-#[cfg(all(test, not(arm_linux)))]
-mod tests {
-    use core::{f32, f64};
-    use qc::{F32, F64};
-
-    check! {
-        fn __addsf3(f: extern "C" fn(f32, f32) -> f32,
-                    a: F32,
-                    b: F32)
-                    -> Option<F32> {
-            Some(F32(f(a.0, b.0)))
-        }
-
-        fn __adddf3(f: extern "C" fn(f64, f64) -> f64,
-                    a: F64,
-                    b: F64) -> Option<F64> {
-            Some(F64(f(a.0, b.0)))
-        }
-    }
-}

+ 1 - 109
src/float/conv.rs

@@ -94,6 +94,7 @@ enum Sign {
     Positive,
     Negative
 }
+
 macro_rules! fp_fix {
     ($intrinsic:ident: $fty:ty, $ity:ty) => {
         pub extern "C" fn $intrinsic(f: $fty) -> $ity {
@@ -155,112 +156,3 @@ fp_fix!(__fixunssfsi: f32, u32);
 fp_fix!(__fixunssfdi: f32, u64);
 fp_fix!(__fixunsdfsi: f64, u32);
 fp_fix!(__fixunsdfdi: f64, u64);
-
-// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
-// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
-// just avoid testing against them on those targets. Do note that our implementation gives the
-// correct answer; gcc_s and compiler-rt are incorrect in this case.
-//
-#[cfg(all(test, not(arm_linux)))]
-mod tests {
-    use qc::{I32, U32, I64, U64, F32, F64};
-
-    check! {
-        fn __floatsisf(f: extern "C" fn(i32) -> f32,
-                    a: I32)
-                    -> Option<F32> {
-            Some(F32(f(a.0)))
-        }
-        fn __floatsidf(f: extern "C" fn(i32) -> f64,
-                    a: I32)
-                    -> Option<F64> {
-            Some(F64(f(a.0)))
-        }
-        fn __floatdidf(f: extern "C" fn(i64) -> f64,
-                    a: I64)
-                    -> Option<F64> {
-            Some(F64(f(a.0)))
-        }
-        fn __floatunsisf(f: extern "C" fn(u32) -> f32,
-                    a: U32)
-                    -> Option<F32> {
-            Some(F32(f(a.0)))
-        }
-        fn __floatunsidf(f: extern "C" fn(u32) -> f64,
-                    a: U32)
-                    -> Option<F64> {
-            Some(F64(f(a.0)))
-        }
-        fn __floatundidf(f: extern "C" fn(u64) -> f64,
-                    a: U64)
-                    -> Option<F64> {
-            Some(F64(f(a.0)))
-        }
-
-        fn __fixsfsi(f: extern "C" fn(f32) -> i32,
-                    a: F32)
-                    -> Option<I32> {
-            if (a.0 as f64) > (i32::max_value() as f64) ||
-                (a.0 as f64) < (i32::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(I32(f(a.0))) }
-        }
-        fn __fixsfdi(f: extern "C" fn(f32) -> i64,
-                    a: F32)
-                    -> Option<I64> {
-            if (a.0 as f64) > (i64::max_value() as f64) ||
-                (a.0 as f64) < (i64::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(I64(f(a.0))) }
-        }
-        fn __fixdfsi(f: extern "C" fn(f64) -> i32,
-                    a: F64)
-                    -> Option<I32> {
-            if a.0 > (i32::max_value() as f64) ||
-               a.0 < (i32::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(I32(f(a.0))) }
-        }
-        fn __fixdfdi(f: extern "C" fn(f64) -> i64,
-                    a: F64)
-                    -> Option<I64> {
-            if a.0 > (i64::max_value() as f64) ||
-               a.0 < (i64::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(I64(f(a.0))) }
-        }
-
-        fn __fixunssfsi(f: extern "C" fn(f32) -> u32,
-                    a: F32)
-                    -> Option<U32> {
-            if (a.0 as f64) > (u32::max_value() as f64) ||
-                (a.0 as f64) < (u32::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(U32(f(a.0))) }
-        }
-        fn __fixunssfdi(f: extern "C" fn(f32) -> u64,
-                    a: F32)
-                    -> Option<U64> {
-            if (a.0 as f64) > (u64::max_value() as f64) ||
-                (a.0 as f64) < (u64::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(U64(f(a.0))) }
-        }
-        fn __fixunsdfsi(f: extern "C" fn(f64) -> u32,
-                    a: F64)
-                    -> Option<U32> {
-            if a.0 > (u32::max_value() as f64) ||
-               a.0 < (u32::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(U32(f(a.0))) }
-        }
-        fn __fixunsdfdi(f: extern "C" fn(f64) -> u64,
-                    a: F64)
-                    -> Option<U64> {
-            if a.0 <= (u64::max_value() as f64) ||
-               a.0 >= (u64::min_value() as f64) || a.0.is_nan() {
-                   None
-           } else { Some(U64(f(a.0))) }
-        }
-    }
-}

+ 0 - 19
src/float/pow.rs

@@ -28,22 +28,3 @@ macro_rules! pow {
 
 pow!(__powisf2: f32, i32);
 pow!(__powidf2: f64, i32);
-
-#[cfg(test)]
-mod tests {
-    use qc::{I32, F32, F64};
-
-    check! {
-        fn __powisf2(f: extern "C" fn(f32, i32) -> f32,
-                     a: F32,
-                     b: I32) -> Option<F32> {
-            Some(F32(f(a.0, b.0)))
-        }
-
-        fn __powidf2(f: extern "C" fn(f64, i32) -> f64,
-                     a: F64,
-                     b: I32) -> Option<F64> {
-            Some(F64(f(a.0, b.0)))
-        }
-    }
-}

+ 0 - 25
src/float/sub.rs

@@ -18,28 +18,3 @@ sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
 sub!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
      #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
      | __subdf3: f64);
-
-// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't
-// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
-// just avoid testing against them on those targets. Do note that our implementation gives the
-// correct answer; gcc_s and compiler-rt are incorrect in this case.
-#[cfg(all(test, not(arm_linux)))]
-mod tests {
-    use core::{f32, f64};
-    use qc::{F32, F64};
-
-    check! {
-        fn __subsf3(f: extern "C" fn(f32, f32) -> f32,
-                    a: F32,
-                    b: F32)
-                    -> Option<F32> {
-            Some(F32(f(a.0, b.0)))
-        }
-
-        fn __subdf3(f: extern "C" fn(f64, f64) -> f64,
-                    a: F64,
-                    b: F64) -> Option<F64> {
-            Some(F64(f(a.0, b.0)))
-        }
-    }
-}

+ 0 - 63
src/int/mul.rs

@@ -93,66 +93,3 @@ mulo!(__mulodi4: i64);
 mulo!(__muloti4: i128, "unadjusted");
 #[cfg(not(all(windows, target_pointer_width="64")))]
 mulo!(__muloti4: i128);
-
-#[cfg(test)]
-mod tests {
-    use qc::{I32, I64, U64};
-
-    check! {
-        fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64)
-                    -> Option<u64> {
-            Some(f(a.0, b.0))
-        }
-
-        fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32,
-                     a: I32,
-                     b: I32) -> Option<(i32, i32)> {
-            let (a, b) = (a.0, b.0);
-            let mut overflow = 2;
-            let r = f(a, b, &mut overflow);
-            if overflow != 0 && overflow != 1 {
-                panic!("Invalid value {} for overflow", overflow);
-            }
-            Some((r, overflow))
-        }
-
-        fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64,
-                     a: I64,
-                     b: I64) -> Option<(i64, i32)> {
-            let (a, b) = (a.0, b.0);
-            let mut overflow = 2;
-            let r = f(a, b, &mut overflow);
-            if overflow != 0 && overflow != 1 {
-                panic!("Invalid value {} for overflow", overflow);
-            }
-            Some((r, overflow))
-        }
-    }
-}
-
-#[cfg(test)]
-#[cfg(all(not(windows),
-          not(target_arch = "mips64"),
-          not(target_arch = "mips64el"),
-          target_pointer_width="64"))]
-mod tests_i128 {
-    use qc::I128;
-
-    check! {
-        fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128)
-                    -> Option<i128> {
-            Some(f(a.0, b.0))
-        }
-        fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128,
-                     a: I128,
-                     b: I128) -> Option<(i128, i32)> {
-            let (a, b) = (a.0, b.0);
-            let mut overflow = 2;
-            let r = f(a, b, &mut overflow);
-            if overflow != 0 && overflow != 1 {
-                panic!("Invalid value {} for overflow", overflow);
-            }
-            Some((r, overflow))
-        }
-    }
-}

+ 0 - 117
src/int/sdiv.rs

@@ -100,120 +100,3 @@ divmod!("aapcs", __divmoddi4, __divdi3: i64);
 
 #[cfg(not(target_arch = "arm"))]
 divmod!("C", __divmoddi4, __divdi3: i64);
-
-#[cfg(test)]
-mod tests {
-    use qc::{U32, U64};
-
-    check! {
-        fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
-            let (n, d) = (n.0 as i64, d.0 as i64);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
-            let (n, d) = (n.0 as i64, d.0 as i64);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        #[cfg(target_arch = "arm")]
-        fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64,
-                       n: U64,
-                       d: U64) -> Option<(i64, i64)> {
-            let (n, d) = (n.0 as i64, d.0 as i64);
-            if d == 0 {
-                None
-            } else {
-                let mut r = 0;
-                let q = f(n, d, &mut r);
-                Some((q, r))
-            }
-        }
-
-        #[cfg(not(target_arch = "arm"))]
-        fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64,
-                       n: U64,
-                       d: U64) -> Option<(i64, i64)> {
-            let (n, d) = (n.0 as i64, d.0 as i64);
-            if d == 0 {
-                None
-            } else {
-                let mut r = 0;
-                let q = f(n, d, &mut r);
-                Some((q, r))
-            }
-        }
-
-        fn __divsi3(f: extern "C" fn(i32, i32) -> i32,
-                    n: U32,
-                    d: U32) -> Option<i32> {
-            let (n, d) = (n.0 as i32, d.0 as i32);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __modsi3(f: extern "C" fn(i32, i32) -> i32,
-                    n: U32,
-                    d: U32) -> Option<i32> {
-            let (n, d) = (n.0 as i32, d.0 as i32);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32,
-                       n: U32,
-                       d: U32) -> Option<(i32, i32)> {
-            let (n, d) = (n.0 as i32, d.0 as i32);
-            if d == 0 {
-                None
-            } else {
-                let mut r = 0;
-                let q = f(n, d, &mut r);
-                Some((q, r))
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-#[cfg(all(not(windows),
-          not(target_arch = "mips64"),
-          not(target_arch = "mips64el"),
-          target_pointer_width="64"))]
-mod tests_i128 {
-    use qc::U128;
-    check! {
-
-        fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
-            let (n, d) = (n.0 as i128, d.0 as i128);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
-            let (n, d) = (n.0 as i128, d.0 as i128);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-    }
-}

+ 0 - 74
src/int/shift.rs

@@ -72,77 +72,3 @@ ashr!(__ashrti3: i128);
 lshr!(__lshrdi3: u64);
 
 lshr!(__lshrti3: u128);
-
-#[cfg(test)]
-mod tests {
-    use qc::{I64, U64};
-
-    // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
-    check! {
-        fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
-            let a = a.0;
-            if b >= 64 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-
-        fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
-            let a = a.0;
-            if b >= 64 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-
-        fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
-            let a = a.0;
-            if b >= 64 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-#[cfg(all(not(windows),
-          not(target_arch = "mips64"),
-          not(target_arch = "mips64el"),
-          target_pointer_width="64"))]
-mod tests_i128 {
-    use qc::{I128, U128};
-
-    // NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
-    check! {
-        fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
-            let a = a.0;
-            if b >= 64 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-
-        fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option<i128> {
-            let a = a.0;
-            if b >= 64 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-
-        fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
-            let a = a.0;
-            if b >= 128 {
-                None
-            } else {
-                Some(f(a, b))
-            }
-        }
-    }
-}

+ 0 - 117
src/int/udiv.rs

@@ -312,120 +312,3 @@ udivmodti4!(::U64x2, ::conv);
 
 #[cfg(not(all(windows, target_pointer_width="64")))]
 udivmodti4!(u128, |i|{ i });
-
-#[cfg(test)]
-mod tests {
-    use qc::{U32, U64};
-
-    check! {
-        fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64,
-                        n: U64,
-                        d: U64) -> Option<(u64, u64)> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                let mut r = 0;
-                let q = f(n, d, Some(&mut r));
-                Some((q, r))
-            }
-        }
-
-        fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32,
-                        n: U32,
-                        d: U32) -> Option<(u32, u32)> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                let mut r = 0;
-                let q = f(n, d, Some(&mut r));
-                Some((q, r))
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-#[cfg(all(not(windows),
-          not(target_arch = "mips64"),
-          not(target_arch = "mips64el"),
-          target_pointer_width="64"))]
-mod tests_i128 {
-    use qc::U128;
-
-    check! {
-        fn __udivti3(f: extern "C" fn(u128, u128) -> u128,
-                     n: U128,
-                     d: U128) -> Option<u128> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __umodti3(f: extern "C" fn(u128, u128) -> u128,
-                     n: U128,
-                     d: U128) -> Option<u128> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                Some(f(n, d))
-            }
-        }
-
-        fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128,
-                        n: U128,
-                        d: U128) -> Option<u128> {
-            let (n, d) = (n.0, d.0);
-            if d == 0 {
-                None
-            } else {
-                // FIXME fix the segfault when the remainder is requested
-                /*let mut r = 0;
-                let q = f(n, d, Some(&mut r));
-                Some((q, r))*/
-                Some(f(n, d, None))
-            }
-        }
-    }
-}

+ 0 - 17
src/lib.rs

@@ -111,26 +111,9 @@ fn sconv(i: i128) -> U64x2 {
     U64x2(j.low(), j.high())
 }
 
-#[cfg(test)]
-#[cfg_attr(target_arch = "arm", macro_use)]
-extern crate quickcheck;
-
 #[cfg(test)]
 extern crate core;
 
-#[cfg(test)]
-extern crate gcc_s;
-
-#[cfg(test)]
-extern crate compiler_rt;
-
-#[cfg(test)]
-extern crate rand;
-
-#[cfg(test)]
-#[macro_use]
-mod qc;
-
 pub mod int;
 pub mod float;
 

+ 8 - 0
tests/adddf3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/adddf3.rs"));

+ 8 - 0
tests/addsf3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/addsf3.rs"));

+ 8 - 0
tests/ashldi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/ashldi3.rs"));

+ 8 - 0
tests/ashlti3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/ashlti3.rs"));

+ 8 - 0
tests/ashrdi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/ashrdi3.rs"));

+ 8 - 0
tests/ashrti3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/ashrti3.rs"));

+ 8 - 0
tests/divdi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/divdi3.rs"));

+ 8 - 0
tests/divmoddi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/divmoddi4.rs"));

+ 8 - 0
tests/divmodsi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/divmodsi4.rs"));

+ 8 - 0
tests/divsi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/divsi3.rs"));

+ 11 - 0
tests/divti3.rs

@@ -0,0 +1,11 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+// FIXME(#158)
+#[cfg(not(any(target_arch = "mips", windows)))]
+include!(concat!(env!("OUT_DIR"), "/divti3.rs"));

+ 8 - 0
tests/fixdfdi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixdfdi.rs"));

+ 8 - 0
tests/fixdfsi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixdfsi.rs"));

+ 8 - 0
tests/fixsfdi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixsfdi.rs"));

+ 8 - 0
tests/fixsfsi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixsfsi.rs"));

+ 8 - 0
tests/fixunsdfdi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixunsdfdi.rs"));

+ 8 - 0
tests/fixunsdfsi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixunsdfsi.rs"));

+ 8 - 0
tests/fixunssfdi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixunssfdi.rs"));

+ 8 - 0
tests/fixunssfsi.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/fixunssfsi.rs"));

+ 8 - 0
tests/floatdidf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatdidf.rs"));

+ 8 - 0
tests/floatsidf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatsidf.rs"));

+ 8 - 0
tests/floatsisf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatsisf.rs"));

+ 8 - 0
tests/floatundidf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatundidf.rs"));

+ 8 - 0
tests/floatunsidf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatunsidf.rs"));

+ 8 - 0
tests/floatunsisf.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/floatunsisf.rs"));

+ 8 - 0
tests/lshrdi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/lshrdi3.rs"));

+ 8 - 0
tests/lshrti3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/lshrti3.rs"));

+ 8 - 0
tests/moddi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/moddi3.rs"));

+ 8 - 0
tests/modsi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/modsi3.rs"));

+ 11 - 0
tests/modti3.rs

@@ -0,0 +1,11 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+// FIXME(#158)
+#[cfg(not(any(target_arch = "mips", windows)))]
+include!(concat!(env!("OUT_DIR"), "/modti3.rs"));

+ 8 - 0
tests/muldi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/muldi3.rs"));

+ 8 - 0
tests/mulodi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/mulodi4.rs"));

+ 8 - 0
tests/mulosi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/mulosi4.rs"));

+ 10 - 0
tests/muloti4.rs

@@ -0,0 +1,10 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+#[cfg(not(target_arch = "mips"))]
+include!(concat!(env!("OUT_DIR"), "/muloti4.rs"));

+ 8 - 0
tests/multi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/multi3.rs"));

+ 8 - 0
tests/powidf2.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/powidf2.rs"));

+ 8 - 0
tests/powisf2.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/powisf2.rs"));

+ 8 - 0
tests/subdf3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/subdf3.rs"));

+ 8 - 0
tests/subsf3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/subsf3.rs"));

+ 8 - 0
tests/udivdi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/udivdi3.rs"));

+ 8 - 0
tests/udivmoddi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/udivmoddi4.rs"));

+ 8 - 0
tests/udivmodsi4.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/udivmodsi4.rs"));

+ 11 - 0
tests/udivmodti4.rs

@@ -0,0 +1,11 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+// FIXME(#158)
+#[cfg(not(any(target_arch = "mips", windows)))]
+include!(concat!(env!("OUT_DIR"), "/udivmodti4.rs"));

+ 8 - 0
tests/udivsi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/udivsi3.rs"));

+ 11 - 0
tests/udivti3.rs

@@ -0,0 +1,11 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+// FIXME(#158)
+#[cfg(not(any(target_arch = "mips", windows)))]
+include!(concat!(env!("OUT_DIR"), "/udivti3.rs"));

+ 8 - 0
tests/umoddi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/umoddi3.rs"));

+ 8 - 0
tests/umodsi3.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+include!(concat!(env!("OUT_DIR"), "/umodsi3.rs"));

+ 11 - 0
tests/umodti3.rs

@@ -0,0 +1,11 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm",
+                not(any(target_env = "gnu", target_env = "musl")),
+                target_os = "linux",
+                test), no_std)]
+
+// FIXME(#137)
+// FIXME(#158)
+#[cfg(not(any(target_arch = "mips", windows)))]
+include!(concat!(env!("OUT_DIR"), "/umodti3.rs"));

+ 27 - 0
thumbv6m-linux-eabi.json

@@ -0,0 +1,27 @@
+{
+    "abi-blacklist": [
+        "stdcall",
+        "fastcall",
+        "vectorcall",
+        "win64",
+        "sysv64"
+    ],
+    "arch": "arm",
+    "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
+    "env": "",
+    "executables": true,
+    "features": "+strict-align",
+    "linker": "arm-none-eabi-gcc",
+    "linker-flavor": "gcc",
+    "llvm-target": "thumbv6m-none-eabi",
+    "max-atomic-width": 0,
+    "os": "linux",
+    "panic-strategy": "abort",
+    "pre-link-args": {
+        "gcc": ["-nostartfiles"]
+    },
+    "relocation-model": "static",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "vendor": ""
+}

+ 26 - 0
thumbv7em-linux-eabi.json

@@ -0,0 +1,26 @@
+{
+    "abi-blacklist": [
+        "stdcall",
+        "fastcall",
+        "vectorcall",
+        "win64",
+        "sysv64"
+    ],
+    "arch": "arm",
+    "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
+    "env": "",
+    "executables": true,
+    "linker": "arm-none-eabi-gcc",
+    "linker-flavor": "gcc",
+    "llvm-target": "thumbv7em-none-eabi",
+    "max-atomic-width": 32,
+    "os": "linux",
+    "panic-strategy": "abort",
+    "pre-link-args": {
+        "gcc": ["-nostartfiles"]
+    },
+    "relocation-model": "static",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "vendor": ""
+}

+ 27 - 0
thumbv7em-linux-eabihf.json

@@ -0,0 +1,27 @@
+{
+    "abi-blacklist": [
+        "stdcall",
+        "fastcall",
+        "vectorcall",
+        "win64",
+        "sysv64"
+    ],
+    "arch": "arm",
+    "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
+    "env": "",
+    "executables": true,
+    "features": "+vfp4,+d16,+fp-only-sp",
+    "linker": "arm-none-eabi-gcc",
+    "linker-flavor": "gcc",
+    "llvm-target": "thumbv7em-none-eabihf",
+    "max-atomic-width": 32,
+    "os": "linux",
+    "panic-strategy": "abort",
+    "pre-link-args": {
+        "gcc": ["-nostartfiles"]
+    },
+    "relocation-model": "static",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "vendor": ""
+}

+ 26 - 0
thumbv7m-linux-eabi.json

@@ -0,0 +1,26 @@
+{
+    "abi-blacklist": [
+        "stdcall",
+        "fastcall",
+        "vectorcall",
+        "win64",
+        "sysv64"
+    ],
+    "arch": "arm",
+    "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
+    "env": "",
+    "executables": true,
+    "linker": "arm-none-eabi-gcc",
+    "linker-flavor": "gcc",
+    "llvm-target": "thumbv7m-none-eabi",
+    "max-atomic-width": 32,
+    "os": "linux",
+    "panic-strategy": "abort",
+    "pre-link-args": {
+        "gcc": ["-nostartfiles"]
+    },
+    "relocation-model": "static",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "vendor": ""
+}