Эх сурвалжийг харах

Merge pull request #210 from scottmcm/add-128bit-lang-items

Implement all the 128-bit operator lang items (Rust 45676 part 2)
Alex Crichton 7 жил өмнө
parent
commit
60d949ba1d

+ 482 - 0
build.rs

@@ -129,6 +129,16 @@ mod tests {
             Divsf3,
             Divdf3,
 
+            // int/addsub.rs
+            AddU128,
+            AddI128,
+            AddoU128,
+            AddoI128,
+            SubU128,
+            SubI128,
+            SuboU128,
+            SuboI128,
+
             // int/mul.rs
             Muldi3,
             Mulodi4,
@@ -341,6 +351,242 @@ fn addsf3() {
         }
     }
 
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct AddU128 {
+        a: u128,
+        b: u128,
+        c: u128,
+    }
+
+    impl TestCase for AddU128 {
+        fn name() -> &'static str {
+            "u128_add"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            let c = a.wrapping_add(b);
+
+            Some(AddU128 { 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::addsub::rust_u128_add;
+
+static TEST_CASES: &[((u128, u128), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn u128_add() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = rust_u128_add(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct AddI128 {
+        a: i128,
+        b: i128,
+        c: i128,
+    }
+
+    impl TestCase for AddI128 {
+        fn name() -> &'static str {
+            "i128_add"
+        }
+
+        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_add(b);
+
+            Some(AddI128 { 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::addsub::rust_i128_add;
+
+static TEST_CASES: &[((i128, i128), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn i128_add() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = rust_i128_add(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct AddoU128 {
+        a: u128,
+        b: u128,
+        c: u128,
+        d: bool,
+    }
+
+    impl TestCase for AddoU128 {
+        fn name() -> &'static str {
+            "u128_addo"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            let (c, d) = a.overflowing_add(b);
+
+            Some(AddoU128 { a, b, c, d })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {d})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                d = self.d
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::addsub::rust_u128_addo;
+
+static TEST_CASES: &[((u128, u128), (u128, bool))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn u128_addo() {
+    for &((a, b), (c, d)) in TEST_CASES {
+        let (c_, d_) = rust_u128_addo(a, b);
+        assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct AddoI128 {
+        a: i128,
+        b: i128,
+        c: i128,
+        d: bool,
+    }
+
+    impl TestCase for AddoI128 {
+        fn name() -> &'static str {
+            "i128_addo"
+        }
+
+        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, d) = a.overflowing_add(b);
+
+            Some(AddoI128 { a, b, c, d })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {d})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                d = self.d
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::addsub::rust_i128_addo;
+
+static TEST_CASES: &[((i128, i128), (i128, bool))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn i128_addo() {
+    for &((a, b), (c, d)) in TEST_CASES {
+        let (c_, d_) = rust_i128_addo(a, b);
+        assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_)));
+    }
+}
+"
+        }
+    }
+
     #[derive(Eq, Hash, PartialEq)]
     pub struct Ashldi3 {
         a: u64,
@@ -3229,6 +3475,242 @@ fn subsf3() {
         }
     }
 
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct SubU128 {
+        a: u128,
+        b: u128,
+        c: u128,
+    }
+
+    impl TestCase for SubU128 {
+        fn name() -> &'static str {
+            "u128_sub"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            let c = a.wrapping_sub(b);
+
+            Some(SubU128 { 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::addsub::rust_u128_sub;
+
+static TEST_CASES: &[((u128, u128), u128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn u128_sub() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = rust_u128_sub(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct SubI128 {
+        a: i128,
+        b: i128,
+        c: i128,
+    }
+
+    impl TestCase for SubI128 {
+        fn name() -> &'static str {
+            "i128_sub"
+        }
+
+        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_sub(b);
+
+            Some(SubI128 { 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::addsub::rust_i128_sub;
+
+static TEST_CASES: &[((i128, i128), i128)] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn i128_sub() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = rust_i128_sub(a, b);
+        assert_eq!(((a, b), c), ((a, b), c_));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct SuboU128 {
+        a: u128,
+        b: u128,
+        c: u128,
+        d: bool,
+    }
+
+    impl TestCase for SuboU128 {
+        fn name() -> &'static str {
+            "u128_subo"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_u128(rng);
+            let b = gen_u128(rng);
+            let (c, d) = a.overflowing_sub(b);
+
+            Some(SuboU128 { a, b, c, d })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {d})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                d = self.d
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::addsub::rust_u128_subo;
+
+static TEST_CASES: &[((u128, u128), (u128, bool))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn u128_subo() {
+    for &((a, b), (c, d)) in TEST_CASES {
+        let (c_, d_) = rust_u128_subo(a, b);
+        assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct SuboI128 {
+        a: i128,
+        b: i128,
+        c: i128,
+        d: bool,
+    }
+
+    impl TestCase for SuboI128 {
+        fn name() -> &'static str {
+            "i128_subo"
+        }
+
+        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, d) = a.overflowing_sub(b);
+
+            Some(SuboI128 { a, b, c, d })
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), ({c}, {d})),",
+                a = self.a,
+                b = self.b,
+                c = self.c,
+                d = self.d
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            "
+use compiler_builtins::int::addsub::rust_i128_subo;
+
+static TEST_CASES: &[((i128, i128), (i128, bool))] = &[
+"
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn i128_subo() {
+    for &((a, b), (c, d)) in TEST_CASES {
+        let (c_, d_) = rust_i128_subo(a, b);
+        assert_eq!(((a, b), (c, d)), ((a, b), (c_, d_)));
+    }
+}
+"
+        }
+    }
+
     #[derive(Eq, Hash, PartialEq)]
     pub struct Mulsf3 {
         a: u32,  // f32

+ 122 - 0
src/int/addsub.rs

@@ -0,0 +1,122 @@
+use int::LargeInt;
+use int::Int;
+
+trait UAddSub: LargeInt {
+    fn uadd(self, other: Self) -> Self {
+        let (low, carry) = self.low().overflowing_add(other.low());
+        let high = self.high().wrapping_add(other.high());
+        let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO };
+        Self::from_parts(low, high.wrapping_add(carry))
+    }
+    fn uadd_one(self) -> Self {
+        let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE);
+        let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO };
+        Self::from_parts(low, self.high().wrapping_add(carry))
+    }
+    fn usub(self, other: Self) -> Self {
+        let uneg = (!other).uadd_one();
+        self.uadd(uneg)
+    }
+}
+
+impl UAddSub for u128 {}
+
+trait AddSub: Int
+    where <Self as Int>::UnsignedInt: UAddSub
+{
+    fn add(self, other: Self) -> Self {
+        Self::from_unsigned(self.unsigned().uadd(other.unsigned()))
+    }
+    fn sub(self, other: Self) -> Self {
+        Self::from_unsigned(self.unsigned().usub(other.unsigned()))
+    }
+}
+
+impl AddSub for u128 {}
+impl AddSub for i128 {}
+
+trait Addo: AddSub
+    where <Self as Int>::UnsignedInt: UAddSub
+{
+    fn addo(self, other: Self, overflow: &mut i32) -> Self {
+        *overflow = 0;
+        let result = AddSub::add(self, other);
+        if other >= Self::ZERO {
+            if result < self {
+                *overflow = 1;
+            }
+        } else {
+            if result >= self {
+                *overflow = 1;
+            }
+        }
+        result
+    }
+}
+
+impl Addo for i128 {}
+impl Addo for u128 {}
+
+trait Subo: AddSub
+    where <Self as Int>::UnsignedInt: UAddSub
+{
+    fn subo(self, other: Self, overflow: &mut i32) -> Self {
+        *overflow = 0;
+        let result = AddSub::sub(self, other);
+        if other >= Self::ZERO {
+            if result > self {
+                *overflow = 1;
+            }
+        } else {
+            if result <= self {
+                *overflow = 1;
+            }
+        }
+        result
+    }
+}
+
+impl Subo for i128 {}
+impl Subo for u128 {}
+
+#[cfg_attr(not(stage0), lang = "i128_add")]
+pub fn rust_i128_add(a: i128, b: i128) -> i128 {
+    rust_u128_add(a as _, b as _) as _
+}
+#[cfg_attr(not(stage0), lang = "i128_addo")]
+pub fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) {
+    let mut oflow = 0;
+    let r = a.addo(b, &mut oflow);
+    (r, oflow != 0)
+}
+#[cfg_attr(not(stage0), lang = "u128_add")]
+pub fn rust_u128_add(a: u128, b: u128) -> u128 {
+    a.add(b)
+}
+#[cfg_attr(not(stage0), lang = "u128_addo")]
+pub fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) {
+    let mut oflow = 0;
+    let r = a.addo(b, &mut oflow);
+    (r, oflow != 0)
+}
+
+#[cfg_attr(not(stage0), lang = "i128_sub")]
+pub fn rust_i128_sub(a: i128, b: i128) -> i128 {
+    rust_u128_sub(a as _, b as _) as _
+}
+#[cfg_attr(not(stage0), lang = "i128_subo")]
+pub fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) {
+    let mut oflow = 0;
+    let r = a.subo(b, &mut oflow);
+    (r, oflow != 0)
+}
+#[cfg_attr(not(stage0), lang = "u128_sub")]
+pub fn rust_u128_sub(a: u128, b: u128) -> u128 {
+    a.sub(b)
+}
+#[cfg_attr(not(stage0), lang = "u128_subo")]
+pub fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) {
+    let mut oflow = 0;
+    let r = a.subo(b, &mut oflow);
+    (r, oflow != 0)
+}

+ 6 - 0
src/int/mod.rs

@@ -12,6 +12,7 @@ macro_rules! os_ty {
     }
 }
 
+pub mod addsub;
 pub mod mul;
 pub mod sdiv;
 pub mod shift;
@@ -72,6 +73,7 @@ pub trait Int:
     fn wrapping_mul(self, other: Self) -> Self;
     fn wrapping_sub(self, other: Self) -> Self;
     fn wrapping_shl(self, other: u32) -> Self;
+    fn overflowing_add(self, other: Self) -> (Self, bool);
     fn aborting_div(self, other: Self) -> Self;
     fn aborting_rem(self, other: Self) -> Self;
     fn leading_zeros(self) -> u32;
@@ -119,6 +121,10 @@ macro_rules! int_impl_common {
                 <Self>::wrapping_shl(self, other)
             }
 
+            fn overflowing_add(self, other: Self) -> (Self, bool) {
+                <Self>::overflowing_add(self, other)
+            }
+
             fn aborting_div(self, other: Self) -> Self {
                 unwrap(<Self>::checked_div(self, other))
             }

+ 33 - 0
src/int/mul.rs

@@ -70,6 +70,18 @@ impl Mulo for i32 {}
 impl Mulo for i64 {}
 impl Mulo for i128 {}
 
+trait UMulo : Int {
+    fn mulo(self, other: Self, overflow: &mut i32) -> Self {
+        *overflow = 0;
+        let result = self.wrapping_mul(other);
+        if self > Self::max_value().aborting_div(other) {
+            *overflow = 1;
+        }
+        result
+    }
+}
+impl UMulo for u128 {}
+
 intrinsics! {
     #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))]
     #[arm_aeabi_alias = __aeabi_lmul]
@@ -95,3 +107,24 @@ intrinsics! {
         a.mulo(b, oflow)
     }
 }
+
+#[cfg_attr(not(stage0), lang = "i128_mul")]
+pub fn rust_i128_mul(a: i128, b: i128) -> i128 {
+    __multi3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "i128_mulo")]
+pub fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) {
+    let mut oflow = 0;
+    let r = __muloti4(a, b, &mut oflow);
+    (r, oflow != 0)
+}
+#[cfg_attr(not(stage0), lang = "u128_mul")]
+pub fn rust_u128_mul(a: u128, b: u128) -> u128 {
+    __multi3(a as _, b as _) as _
+}
+#[cfg_attr(not(stage0), lang = "u128_mulo")]
+pub fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) {
+    let mut oflow = 0;
+    let r = a.mulo(b, &mut oflow);
+    (r, oflow != 0)
+}

+ 9 - 0
src/int/sdiv.rs

@@ -97,3 +97,12 @@ intrinsics! {
         a.divmod(b, rem, |a, b| __divdi3(a, b))
     }
 }
+
+#[cfg_attr(not(stage0), lang = "i128_div")]
+pub fn rust_i128_div(a: i128, b: i128) -> i128 {
+    __divti3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "i128_rem")]
+pub fn rust_i128_rem(a: i128, b: i128) -> i128 {
+    __modti3(a, b)
+}

+ 34 - 0
src/int/shift.rs

@@ -95,3 +95,37 @@ intrinsics! {
         a.lshr(b)
     }
 }
+
+#[cfg_attr(not(stage0), lang = "i128_shl")]
+pub fn rust_i128_shl(a: i128, b: u32) -> i128 {
+    __ashlti3(a as _, b) as _
+}
+#[cfg_attr(not(stage0), lang = "i128_shlo")]
+pub fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) {
+    (rust_i128_shl(a, b as _), b >= 128)
+}
+#[cfg_attr(not(stage0), lang = "u128_shl")]
+pub fn rust_u128_shl(a: u128, b: u32) -> u128 {
+    __ashlti3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "u128_shlo")]
+pub fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) {
+    (rust_u128_shl(a, b as _), b >= 128)
+}
+
+#[cfg_attr(not(stage0), lang = "i128_shr")]
+pub fn rust_i128_shr(a: i128, b: u32) -> i128 {
+    __ashrti3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "i128_shro")]
+pub fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) {
+    (rust_i128_shr(a, b as _), b >= 128)
+}
+#[cfg_attr(not(stage0), lang = "u128_shr")]
+pub fn rust_u128_shr(a: u128, b: u32) -> u128 {
+    __lshrti3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "u128_shro")]
+pub fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) {
+    (rust_u128_shr(a, b as _), b >= 128)
+}

+ 9 - 0
src/int/udiv.rs

@@ -269,3 +269,12 @@ intrinsics! {
         udivmod_inner!(n, d, rem, u128)
     }
 }
+
+#[cfg_attr(not(stage0), lang = "u128_div")]
+pub fn rust_u128_div(a: u128, b: u128) -> u128 {
+    __udivti3(a, b)
+}
+#[cfg_attr(not(stage0), lang = "u128_rem")]
+pub fn rust_u128_rem(a: u128, b: u128) -> u128 {
+    __umodti3(a, b)
+}

+ 1 - 0
src/lib.rs

@@ -17,6 +17,7 @@
 #![feature(repr_simd)]
 #![feature(abi_unadjusted)]
 #![feature(linkage)]
+#![feature(lang_items)]
 #![allow(unused_features)]
 #![no_builtins]
 #![unstable(feature = "compiler_builtins_lib",

+ 8 - 0
tests/i128_add.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"), "/i128_add.rs"));

+ 8 - 0
tests/i128_addo.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"), "/i128_addo.rs"));

+ 8 - 0
tests/i128_sub.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"), "/i128_sub.rs"));

+ 8 - 0
tests/i128_subo.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"), "/i128_subo.rs"));

+ 8 - 0
tests/u128_add.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"), "/u128_add.rs"));

+ 8 - 0
tests/u128_addo.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"), "/u128_addo.rs"));

+ 8 - 0
tests/u128_sub.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"), "/u128_sub.rs"));

+ 8 - 0
tests/u128_subo.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"), "/u128_subo.rs"));