+258
| rust-lang/libm as a whole is available for use under the MIT license: | ||
| ------------------------------------------------------------------------------ | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| ------------------------------------------------------------------------------ | ||
| As a contributor, you agree that your code can be used under either the MIT | ||
| license or the Apache-2.0 license: | ||
| ------------------------------------------------------------------------------ | ||
| Apache License | ||
| Version 2.0, January 2004 | ||
| http://www.apache.org/licenses/ | ||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||
| 1. Definitions. | ||
| "License" shall mean the terms and conditions for use, reproduction, | ||
| and distribution as defined by Sections 1 through 9 of this document. | ||
| "Licensor" shall mean the copyright owner or entity authorized by | ||
| the copyright owner that is granting the License. | ||
| "Legal Entity" shall mean the union of the acting entity and all | ||
| other entities that control, are controlled by, or are under common | ||
| control with that entity. For the purposes of this definition, | ||
| "control" means (i) the power, direct or indirect, to cause the | ||
| direction or management of such entity, whether by contract or | ||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||
| outstanding shares, or (iii) beneficial ownership of such entity. | ||
| "You" (or "Your") shall mean an individual or Legal Entity | ||
| exercising permissions granted by this License. | ||
| "Source" form shall mean the preferred form for making modifications, | ||
| including but not limited to software source code, documentation | ||
| source, and configuration files. | ||
| "Object" form shall mean any form resulting from mechanical | ||
| transformation or translation of a Source form, including but | ||
| not limited to compiled object code, generated documentation, | ||
| and conversions to other media types. | ||
| "Work" shall mean the work of authorship, whether in Source or | ||
| Object form, made available under the License, as indicated by a | ||
| copyright notice that is included in or attached to the work | ||
| (an example is provided in the Appendix below). | ||
| "Derivative Works" shall mean any work, whether in Source or Object | ||
| form, that is based on (or derived from) the Work and for which the | ||
| editorial revisions, annotations, elaborations, or other modifications | ||
| represent, as a whole, an original work of authorship. For the purposes | ||
| of this License, Derivative Works shall not include works that remain | ||
| separable from, or merely link (or bind by name) to the interfaces of, | ||
| the Work and Derivative Works thereof. | ||
| "Contribution" shall mean any work of authorship, including | ||
| the original version of the Work and any modifications or additions | ||
| to that Work or Derivative Works thereof, that is intentionally | ||
| submitted to Licensor for inclusion in the Work by the copyright owner | ||
| or by an individual or Legal Entity authorized to submit on behalf of | ||
| the copyright owner. For the purposes of this definition, "submitted" | ||
| means any form of electronic, verbal, or written communication sent | ||
| to the Licensor or its representatives, including but not limited to | ||
| communication on electronic mailing lists, source code control systems, | ||
| and issue tracking systems that are managed by, or on behalf of, the | ||
| Licensor for the purpose of discussing and improving the Work, but | ||
| excluding communication that is conspicuously marked or otherwise | ||
| designated in writing by the copyright owner as "Not a Contribution." | ||
| "Contributor" shall mean Licensor and any individual or Legal Entity | ||
| on behalf of whom a Contribution has been received by Licensor and | ||
| subsequently incorporated within the Work. | ||
| 2. Grant of Copyright License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| copyright license to reproduce, prepare Derivative Works of, | ||
| publicly display, publicly perform, sublicense, and distribute the | ||
| Work and such Derivative Works in Source or Object form. | ||
| 3. Grant of Patent License. Subject to the terms and conditions of | ||
| this License, each Contributor hereby grants to You a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||
| (except as stated in this section) patent license to make, have made, | ||
| use, offer to sell, sell, import, and otherwise transfer the Work, | ||
| where such license applies only to those patent claims licensable | ||
| by such Contributor that are necessarily infringed by their | ||
| Contribution(s) alone or by combination of their Contribution(s) | ||
| with the Work to which such Contribution(s) was submitted. If You | ||
| institute patent litigation against any entity (including a | ||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | ||
| or a Contribution incorporated within the Work constitutes direct | ||
| or contributory patent infringement, then any patent licenses | ||
| granted to You under this License for that Work shall terminate | ||
| as of the date such litigation is filed. | ||
| 4. Redistribution. You may reproduce and distribute copies of the | ||
| Work or Derivative Works thereof in any medium, with or without | ||
| modifications, and in Source or Object form, provided that You | ||
| meet the following conditions: | ||
| (a) You must give any other recipients of the Work or | ||
| Derivative Works a copy of this License; and | ||
| (b) You must cause any modified files to carry prominent notices | ||
| stating that You changed the files; and | ||
| (c) You must retain, in the Source form of any Derivative Works | ||
| that You distribute, all copyright, patent, trademark, and | ||
| attribution notices from the Source form of the Work, | ||
| excluding those notices that do not pertain to any part of | ||
| the Derivative Works; and | ||
| (d) If the Work includes a "NOTICE" text file as part of its | ||
| distribution, then any Derivative Works that You distribute must | ||
| include a readable copy of the attribution notices contained | ||
| within such NOTICE file, excluding those notices that do not | ||
| pertain to any part of the Derivative Works, in at least one | ||
| of the following places: within a NOTICE text file distributed | ||
| as part of the Derivative Works; within the Source form or | ||
| documentation, if provided along with the Derivative Works; or, | ||
| within a display generated by the Derivative Works, if and | ||
| wherever such third-party notices normally appear. The contents | ||
| of the NOTICE file are for informational purposes only and | ||
| do not modify the License. You may add Your own attribution | ||
| notices within Derivative Works that You distribute, alongside | ||
| or as an addendum to the NOTICE text from the Work, provided | ||
| that such additional attribution notices cannot be construed | ||
| as modifying the License. | ||
| You may add Your own copyright statement to Your modifications and | ||
| may provide additional or different license terms and conditions | ||
| for use, reproduction, or distribution of Your modifications, or | ||
| for any such Derivative Works as a whole, provided Your use, | ||
| reproduction, and distribution of the Work otherwise complies with | ||
| the conditions stated in this License. | ||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | ||
| any Contribution intentionally submitted for inclusion in the Work | ||
| by You to the Licensor shall be under the terms and conditions of | ||
| this License, without any additional terms or conditions. | ||
| Notwithstanding the above, nothing herein shall supersede or modify | ||
| the terms of any separate license agreement you may have executed | ||
| with Licensor regarding such Contributions. | ||
| 6. Trademarks. This License does not grant permission to use the trade | ||
| names, trademarks, service marks, or product names of the Licensor, | ||
| except as required for reasonable and customary use in describing the | ||
| origin of the Work and reproducing the content of the NOTICE file. | ||
| 7. Disclaimer of Warranty. Unless required by applicable law or | ||
| agreed to in writing, Licensor provides the Work (and each | ||
| Contributor provides its Contributions) on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied, including, without limitation, any warranties or conditions | ||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||
| PARTICULAR PURPOSE. You are solely responsible for determining the | ||
| appropriateness of using or redistributing the Work and assume any | ||
| risks associated with Your exercise of permissions under this License. | ||
| 8. Limitation of Liability. In no event and under no legal theory, | ||
| whether in tort (including negligence), contract, or otherwise, | ||
| unless required by applicable law (such as deliberate and grossly | ||
| negligent acts) or agreed to in writing, shall any Contributor be | ||
| liable to You for damages, including any direct, indirect, special, | ||
| incidental, or consequential damages of any character arising as a | ||
| result of this License or out of the use or inability to use the | ||
| Work (including but not limited to damages for loss of goodwill, | ||
| work stoppage, computer failure or malfunction, or any and all | ||
| other commercial damages or losses), even if such Contributor | ||
| has been advised of the possibility of such damages. | ||
| 9. Accepting Warranty or Additional Liability. While redistributing | ||
| the Work or Derivative Works thereof, You may choose to offer, | ||
| and charge a fee for, acceptance of support, warranty, indemnity, | ||
| or other liability obligations and/or rights consistent with this | ||
| License. However, in accepting such obligations, You may act only | ||
| on Your own behalf and on Your sole responsibility, not on behalf | ||
| of any other Contributor, and only if You agree to indemnify, | ||
| defend, and hold each Contributor harmless for any liability | ||
| incurred by, or claims asserted against, such Contributor by reason | ||
| of your accepting any such warranty or additional liability. | ||
| END OF TERMS AND CONDITIONS | ||
| APPENDIX: How to apply the Apache License to your work. | ||
| To apply the Apache License to your work, attach the following | ||
| boilerplate notice, with the fields enclosed by brackets "[]" | ||
| replaced with your own identifying information. (Don't include | ||
| the brackets!) The text should be enclosed in the appropriate | ||
| comment syntax for the file format. We also recommend that a | ||
| file or class name and description of purpose be included on the | ||
| same "printed page" as the copyright notice for easier | ||
| identification within third-party archives. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| ------------------------------------------------------------------------------ | ||
| This Rust library contains the following copyrights: | ||
| Copyright (c) 2018 Jorge Aparicio | ||
| Portions of this software are derived from third-party works licensed under | ||
| terms compatible with the above MIT license: | ||
| * musl libc https://www.musl-libc.org/. This library contains the following | ||
| copyright: | ||
| Copyright © 2005-2020 Rich Felker, et al. | ||
| * The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH | ||
| routines are available under the MIT license on a per-file basis. | ||
| The musl libc COPYRIGHT file also includes the following notice relevant to | ||
| math portions of the library: | ||
| ------------------------------------------------------------------------------ | ||
| Much of the math library code (src/math/* and src/complex/*) is | ||
| Copyright © 1993,2004 Sun Microsystems or | ||
| Copyright © 2003-2011 David Schultz or | ||
| Copyright © 2003-2009 Steven G. Kargl or | ||
| Copyright © 2003-2009 Bruce D. Evans or | ||
| Copyright © 2008 Stephen L. Moshier or | ||
| Copyright © 2017-2018 Arm Limited | ||
| and labelled as such in comments in the individual source files. All | ||
| have been licensed under extremely permissive terms. | ||
| ------------------------------------------------------------------------------ | ||
| Copyright notices are retained in src/* files where relevant. |
| { | ||
| "git": { | ||
| "sha1": "721a5edc1be6b0412e4b1704590aed76f9a55899" | ||
| "sha1": "114f90ff8a7708586e58dd7c0ed7d2c3f7a91ab1" | ||
| }, | ||
| "path_in_vcs": "" | ||
| } |
+4
-450
@@ -5,6 +5,8 @@ use std::env; | ||
| println!("cargo:rerun-if-changed=build.rs"); | ||
| println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); | ||
| println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); | ||
| #[cfg(feature = "musl-reference-tests")] | ||
| musl_reference_tests::generate(); | ||
| println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); | ||
| #[allow(unexpected_cfgs)] | ||
| if !cfg!(feature = "checked") { | ||
@@ -17,449 +19,1 @@ let lvl = env::var("OPT_LEVEL").unwrap(); | ||
| } | ||
| #[cfg(feature = "musl-reference-tests")] | ||
| mod musl_reference_tests { | ||
| use rand::seq::SliceRandom; | ||
| use rand::Rng; | ||
| use std::env; | ||
| use std::fs; | ||
| use std::process::Command; | ||
| // Number of tests to generate for each function | ||
| const NTESTS: usize = 500; | ||
| // These files are all internal functions or otherwise miscellaneous, not | ||
| // defining a function we want to test. | ||
| const IGNORED_FILES: &[&str] = &[ | ||
| "fenv.rs", | ||
| // These are giving slightly different results compared to musl | ||
| "lgamma.rs", | ||
| "lgammaf.rs", | ||
| "tgamma.rs", | ||
| "j0.rs", | ||
| "j0f.rs", | ||
| "jn.rs", | ||
| "jnf.rs", | ||
| "j1.rs", | ||
| "j1f.rs", | ||
| ]; | ||
| struct Function { | ||
| name: String, | ||
| args: Vec<Ty>, | ||
| ret: Vec<Ty>, | ||
| tests: Vec<Test>, | ||
| } | ||
| enum Ty { | ||
| F32, | ||
| F64, | ||
| I32, | ||
| Bool, | ||
| } | ||
| struct Test { | ||
| inputs: Vec<i64>, | ||
| outputs: Vec<i64>, | ||
| } | ||
| pub fn generate() { | ||
| // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 | ||
| let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); | ||
| if target_arch == "powerpc64" { | ||
| return; | ||
| } | ||
| let files = fs::read_dir("src/math") | ||
| .unwrap() | ||
| .map(|f| f.unwrap().path()) | ||
| .collect::<Vec<_>>(); | ||
| let mut math = Vec::new(); | ||
| for file in files { | ||
| if IGNORED_FILES.iter().any(|f| file.ends_with(f)) { | ||
| continue; | ||
| } | ||
| println!("generating musl reference tests in {:?}", file); | ||
| let contents = fs::read_to_string(file).unwrap(); | ||
| let mut functions = contents.lines().filter(|f| f.starts_with("pub fn")); | ||
| while let Some(function_to_test) = functions.next() { | ||
| math.push(parse(function_to_test)); | ||
| } | ||
| } | ||
| // Generate a bunch of random inputs for each function. This will | ||
| // attempt to generate a good set of uniform test cases for exercising | ||
| // all the various functionality. | ||
| generate_random_tests(&mut math, &mut rand::thread_rng()); | ||
| // After we have all our inputs, use the x86_64-unknown-linux-musl | ||
| // target to generate the expected output. | ||
| generate_test_outputs(&mut math); | ||
| //panic!("Boo"); | ||
| // ... and now that we have both inputs and expected outputs, do a bunch | ||
| // of codegen to create the unit tests which we'll actually execute. | ||
| generate_unit_tests(&math); | ||
| } | ||
| /// A "poor man's" parser for the signature of a function | ||
| fn parse(s: &str) -> Function { | ||
| let s = eat(s, "pub fn "); | ||
| let pos = s.find('(').unwrap(); | ||
| let name = &s[..pos]; | ||
| let s = &s[pos + 1..]; | ||
| let end = s.find(')').unwrap(); | ||
| let args = s[..end] | ||
| .split(',') | ||
| .map(|arg| { | ||
| let colon = arg.find(':').unwrap(); | ||
| parse_ty(arg[colon + 1..].trim()) | ||
| }) | ||
| .collect::<Vec<_>>(); | ||
| let tail = &s[end + 1..]; | ||
| let tail = eat(tail, " -> "); | ||
| let ret = parse_retty(tail.replace("{", "").trim()); | ||
| return Function { | ||
| name: name.to_string(), | ||
| args, | ||
| ret, | ||
| tests: Vec::new(), | ||
| }; | ||
| fn parse_ty(s: &str) -> Ty { | ||
| match s { | ||
| "f32" => Ty::F32, | ||
| "f64" => Ty::F64, | ||
| "i32" => Ty::I32, | ||
| "bool" => Ty::Bool, | ||
| other => panic!("unknown type `{}`", other), | ||
| } | ||
| } | ||
| fn parse_retty(s: &str) -> Vec<Ty> { | ||
| match s { | ||
| "(f32, f32)" => vec![Ty::F32, Ty::F32], | ||
| "(f32, i32)" => vec![Ty::F32, Ty::I32], | ||
| "(f64, f64)" => vec![Ty::F64, Ty::F64], | ||
| "(f64, i32)" => vec![Ty::F64, Ty::I32], | ||
| other => vec![parse_ty(other)], | ||
| } | ||
| } | ||
| fn eat<'a>(s: &'a str, prefix: &str) -> &'a str { | ||
| if s.starts_with(prefix) { | ||
| &s[prefix.len()..] | ||
| } else { | ||
| panic!("{:?} didn't start with {:?}", s, prefix) | ||
| } | ||
| } | ||
| } | ||
| fn generate_random_tests<R: Rng>(functions: &mut [Function], rng: &mut R) { | ||
| for function in functions { | ||
| for _ in 0..NTESTS { | ||
| function.tests.push(generate_test(function, rng)); | ||
| } | ||
| } | ||
| fn generate_test<R: Rng>(function: &Function, rng: &mut R) -> Test { | ||
| let mut inputs = function | ||
| .args | ||
| .iter() | ||
| .map(|ty| ty.gen_i64(rng)) | ||
| .collect::<Vec<_>>(); | ||
| // First argument to this function appears to be a number of | ||
| // iterations, so passing in massive random numbers causes it to | ||
| // take forever to execute, so make sure we're not running random | ||
| // math code until the heat death of the universe. | ||
| if function.name == "jn" || function.name == "jnf" { | ||
| inputs[0] &= 0xffff; | ||
| } | ||
| Test { | ||
| inputs, | ||
| // zero output for now since we'll generate it later | ||
| outputs: vec![], | ||
| } | ||
| } | ||
| } | ||
| impl Ty { | ||
| fn gen_i64<R: Rng>(&self, r: &mut R) -> i64 { | ||
| use std::f32; | ||
| use std::f64; | ||
| return match self { | ||
| Ty::F32 => { | ||
| if r.gen_range(0, 20) < 1 { | ||
| let i = *[f32::NAN, f32::INFINITY, f32::NEG_INFINITY] | ||
| .choose(r) | ||
| .unwrap(); | ||
| i.to_bits().into() | ||
| } else { | ||
| r.gen::<f32>().to_bits().into() | ||
| } | ||
| } | ||
| Ty::F64 => { | ||
| if r.gen_range(0, 20) < 1 { | ||
| let i = *[f64::NAN, f64::INFINITY, f64::NEG_INFINITY] | ||
| .choose(r) | ||
| .unwrap(); | ||
| i.to_bits() as i64 | ||
| } else { | ||
| r.gen::<f64>().to_bits() as i64 | ||
| } | ||
| } | ||
| Ty::I32 => { | ||
| if r.gen_range(0, 10) < 1 { | ||
| let i = *[i32::max_value(), 0, i32::min_value()].choose(r).unwrap(); | ||
| i.into() | ||
| } else { | ||
| r.gen::<i32>().into() | ||
| } | ||
| } | ||
| Ty::Bool => r.gen::<bool>() as i64, | ||
| }; | ||
| } | ||
| fn libc_ty(&self) -> &'static str { | ||
| match self { | ||
| Ty::F32 => "f32", | ||
| Ty::F64 => "f64", | ||
| Ty::I32 => "i32", | ||
| Ty::Bool => "i32", | ||
| } | ||
| } | ||
| fn libc_pty(&self) -> &'static str { | ||
| match self { | ||
| Ty::F32 => "*mut f32", | ||
| Ty::F64 => "*mut f64", | ||
| Ty::I32 => "*mut i32", | ||
| Ty::Bool => "*mut i32", | ||
| } | ||
| } | ||
| fn default(&self) -> &'static str { | ||
| match self { | ||
| Ty::F32 => "0_f32", | ||
| Ty::F64 => "0_f64", | ||
| Ty::I32 => "0_i32", | ||
| Ty::Bool => "false", | ||
| } | ||
| } | ||
| fn to_i64(&self) -> &'static str { | ||
| match self { | ||
| Ty::F32 => ".to_bits() as i64", | ||
| Ty::F64 => ".to_bits() as i64", | ||
| Ty::I32 => " as i64", | ||
| Ty::Bool => " as i64", | ||
| } | ||
| } | ||
| } | ||
| fn generate_test_outputs(functions: &mut [Function]) { | ||
| let mut src = String::new(); | ||
| let dst = std::env::var("OUT_DIR").unwrap(); | ||
| // Generate a program which will run all tests with all inputs in | ||
| // `functions`. This program will write all outputs to stdout (in a | ||
| // binary format). | ||
| src.push_str("use std::io::Write;"); | ||
| src.push_str("fn main() {"); | ||
| src.push_str("let mut result = Vec::new();"); | ||
| for function in functions.iter_mut() { | ||
| src.push_str("unsafe {"); | ||
| src.push_str("extern { fn "); | ||
| src.push_str(&function.name); | ||
| src.push_str("("); | ||
| let (ret, retptr) = match function.name.as_str() { | ||
| "sincos" | "sincosf" => (None, &function.ret[..]), | ||
| _ => (Some(&function.ret[0]), &function.ret[1..]), | ||
| }; | ||
| for (i, arg) in function.args.iter().enumerate() { | ||
| src.push_str(&format!("arg{}: {},", i, arg.libc_ty())); | ||
| } | ||
| for (i, ret) in retptr.iter().enumerate() { | ||
| src.push_str(&format!("argret{}: {},", i, ret.libc_pty())); | ||
| } | ||
| src.push_str(")"); | ||
| if let Some(ty) = ret { | ||
| src.push_str(" -> "); | ||
| src.push_str(ty.libc_ty()); | ||
| } | ||
| src.push_str("; }"); | ||
| src.push_str(&format!("static TESTS: &[[i64; {}]]", function.args.len())); | ||
| src.push_str(" = &["); | ||
| for test in function.tests.iter() { | ||
| src.push_str("["); | ||
| for val in test.inputs.iter() { | ||
| src.push_str(&val.to_string()); | ||
| src.push_str(","); | ||
| } | ||
| src.push_str("],"); | ||
| } | ||
| src.push_str("];"); | ||
| src.push_str("for test in TESTS {"); | ||
| for (i, arg) in retptr.iter().enumerate() { | ||
| src.push_str(&format!("let mut argret{} = {};", i, arg.default())); | ||
| } | ||
| src.push_str("let output = "); | ||
| src.push_str(&function.name); | ||
| src.push_str("("); | ||
| for (i, arg) in function.args.iter().enumerate() { | ||
| src.push_str(&match arg { | ||
| Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), | ||
| Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), | ||
| Ty::I32 => format!("test[{}] as i32", i), | ||
| Ty::Bool => format!("test[{}] as i32", i), | ||
| }); | ||
| src.push_str(","); | ||
| } | ||
| for (i, _) in retptr.iter().enumerate() { | ||
| src.push_str(&format!("&mut argret{},", i)); | ||
| } | ||
| src.push_str(");"); | ||
| if let Some(ty) = &ret { | ||
| src.push_str(&format!("let output = output{};", ty.to_i64())); | ||
| src.push_str("result.extend_from_slice(&output.to_le_bytes());"); | ||
| } | ||
| for (i, ret) in retptr.iter().enumerate() { | ||
| src.push_str(&format!( | ||
| "result.extend_from_slice(&(argret{}{}).to_le_bytes());", | ||
| i, | ||
| ret.to_i64(), | ||
| )); | ||
| } | ||
| src.push_str("}"); | ||
| src.push_str("}"); | ||
| } | ||
| src.push_str("std::io::stdout().write_all(&result).unwrap();"); | ||
| src.push_str("}"); | ||
| let path = format!("{}/gen.rs", dst); | ||
| fs::write(&path, src).unwrap(); | ||
| // Make it somewhat pretty if something goes wrong | ||
| drop(Command::new("rustfmt").arg(&path).status()); | ||
| // Compile and execute this tests for the musl target, assuming we're an | ||
| // x86_64 host effectively. | ||
| let status = Command::new("rustc") | ||
| .current_dir(&dst) | ||
| .arg(&path) | ||
| .arg("--target=x86_64-unknown-linux-musl") | ||
| .status() | ||
| .unwrap(); | ||
| assert!(status.success()); | ||
| let output = Command::new("./gen").current_dir(&dst).output().unwrap(); | ||
| assert!(output.status.success()); | ||
| assert!(output.stderr.is_empty()); | ||
| // Map all the output bytes back to an `i64` and then shove it all into | ||
| // the expected results. | ||
| let mut results = output.stdout.chunks_exact(8).map(|buf| { | ||
| let mut exact = [0; 8]; | ||
| exact.copy_from_slice(buf); | ||
| i64::from_le_bytes(exact) | ||
| }); | ||
| for f in functions.iter_mut() { | ||
| for test in f.tests.iter_mut() { | ||
| test.outputs = (0..f.ret.len()).map(|_| results.next().unwrap()).collect(); | ||
| } | ||
| } | ||
| assert!(results.next().is_none()); | ||
| } | ||
| /// Codegens a file which has a ton of `#[test]` annotations for all the | ||
| /// tests that we generated above. | ||
| fn generate_unit_tests(functions: &[Function]) { | ||
| let mut src = String::new(); | ||
| let dst = std::env::var("OUT_DIR").unwrap(); | ||
| for function in functions { | ||
| src.push_str("#[test]"); | ||
| src.push_str("fn "); | ||
| src.push_str(&function.name); | ||
| src.push_str("_matches_musl() {"); | ||
| src.push_str(&format!( | ||
| "static TESTS: &[([i64; {}], [i64; {}])]", | ||
| function.args.len(), | ||
| function.ret.len(), | ||
| )); | ||
| src.push_str(" = &["); | ||
| for test in function.tests.iter() { | ||
| src.push_str("(["); | ||
| for val in test.inputs.iter() { | ||
| src.push_str(&val.to_string()); | ||
| src.push_str(","); | ||
| } | ||
| src.push_str("],"); | ||
| src.push_str("["); | ||
| for val in test.outputs.iter() { | ||
| src.push_str(&val.to_string()); | ||
| src.push_str(","); | ||
| } | ||
| src.push_str("],"); | ||
| src.push_str("),"); | ||
| } | ||
| src.push_str("];"); | ||
| src.push_str("for (test, expected) in TESTS {"); | ||
| src.push_str("let output = "); | ||
| src.push_str(&function.name); | ||
| src.push_str("("); | ||
| for (i, arg) in function.args.iter().enumerate() { | ||
| src.push_str(&match arg { | ||
| Ty::F32 => format!("f32::from_bits(test[{}] as u32)", i), | ||
| Ty::F64 => format!("f64::from_bits(test[{}] as u64)", i), | ||
| Ty::I32 => format!("test[{}] as i32", i), | ||
| Ty::Bool => format!("test[{}] as i32", i), | ||
| }); | ||
| src.push_str(","); | ||
| } | ||
| src.push_str(");"); | ||
| for (i, ret) in function.ret.iter().enumerate() { | ||
| let get = if function.ret.len() == 1 { | ||
| String::new() | ||
| } else { | ||
| format!(".{}", i) | ||
| }; | ||
| src.push_str(&(match ret { | ||
| Ty::F32 => format!("if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}", get, i), | ||
| Ty::F64 => format!("if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}", get, i), | ||
| Ty::I32 => format!("if output{} as i64 == expected[{}] {{ continue }}", get, i), | ||
| Ty::Bool => unreachable!(), | ||
| })); | ||
| } | ||
| src.push_str( | ||
| r#" | ||
| panic!("INPUT: {:?} EXPECTED: {:?} ACTUAL {:?}", test, expected, output); | ||
| "#, | ||
| ); | ||
| src.push_str("}"); | ||
| src.push_str("}"); | ||
| } | ||
| let path = format!("{}/musl-tests.rs", dst); | ||
| fs::write(&path, src).unwrap(); | ||
| // Try to make it somewhat pretty | ||
| drop(Command::new("rustfmt").arg(&path).status()); | ||
| } | ||
| } |
+15
-9
@@ -13,6 +13,7 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| [package] | ||
| edition = "2018" | ||
| edition = "2021" | ||
| name = "libm" | ||
| version = "0.2.8" | ||
| version = "0.2.9" | ||
| authors = ["Jorge Aparicio <jorge@japaric.io>"] | ||
| build = "build.rs" | ||
| exclude = [ | ||
@@ -22,2 +23,7 @@ "/ci/", | ||
| ] | ||
| autolib = false | ||
| autobins = false | ||
| autoexamples = false | ||
| autotests = false | ||
| autobenches = false | ||
| description = "libm in pure Rust" | ||
@@ -31,3 +37,3 @@ documentation = "https://docs.rs/libm" | ||
| categories = ["no-std"] | ||
| license = "MIT OR Apache-2.0" | ||
| license = "MIT AND (MIT OR Apache-2.0)" | ||
| repository = "https://github.com/rust-lang/libm" | ||
@@ -38,12 +44,12 @@ | ||
| [lib] | ||
| name = "libm" | ||
| path = "src/lib.rs" | ||
| [dev-dependencies.no-panic] | ||
| version = "0.1.8" | ||
| version = "0.1.30" | ||
| [build-dependencies.rand] | ||
| version = "0.6.5" | ||
| optional = true | ||
| [features] | ||
| default = [] | ||
| musl-reference-tests = ["rand"] | ||
| force-soft-floats = [] | ||
| unstable = [] |
+36
-3
@@ -1,13 +0,42 @@ | ||
| # Change Log | ||
| # Changelog | ||
| All notable changes to this project will be documented in this file. | ||
| This project adheres to [Semantic Versioning](http://semver.org/). | ||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| and this project adheres to | ||
| [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
| ## [Unreleased] | ||
| ... | ||
| ## [0.2.9](https://github.com/rust-lang/libm/compare/libm-v0.2.8...libm-v0.2.9) - 2024-10-26 | ||
| ### Fixed | ||
| - Update exponent calculations in nextafter to match musl | ||
| ### Changed | ||
| - Update licensing to MIT AND (MIT OR Apache-2.0), as this is derivative from | ||
| MIT-licensed musl. | ||
| - Set edition to 2021 for all crates | ||
| - Upgrade all dependencies | ||
| ### Other | ||
| - Don't deny warnings in lib.rs | ||
| - Rename the `musl-bitwise-tests` feature to `test-musl-serialized` | ||
| - Rename the `musl-reference-tests` feature to `musl-bitwise-tests` | ||
| - Move `musl-reference-tests` to a new `libm-test` crate | ||
| - Add a `force-soft-floats` feature to prevent using any intrinsics or | ||
| arch-specific code | ||
| - Deny warnings in CI | ||
| - Fix `clippy::deprecated_cfg_attr` on compiler_builtins | ||
| - Corrected English typos | ||
| - Remove unneeded `extern core` in `tgamma` | ||
| - Allow internal_features lint when building with "unstable" | ||
| ## [v0.2.1] - 2019-11-22 | ||
| ### Fixed | ||
| - sincosf | ||
@@ -18,2 +47,3 @@ | ||
| ### Added | ||
| - Benchmarks | ||
@@ -27,2 +57,3 @@ - signum | ||
| ### Fixed | ||
| - Rounding to negative zero | ||
@@ -34,2 +65,3 @@ - Overflows in rem_pio2 and remquo | ||
| ### Removed | ||
| - F32Ext and F64Ext traits | ||
@@ -40,2 +72,3 @@ | ||
| ### Fixed | ||
| - Restored compatibility with Rust 1.31.0 | ||
@@ -42,0 +75,0 @@ |
+4
-4
@@ -10,3 +10,3 @@ # How to contribute | ||
| - Run `cargo test` to make sure it works | ||
| - Run `cargo test --features musl-reference-tests` to compare your | ||
| - Run `cargo test --features libm-test/test-musl-serialized` to compare your | ||
| implementation against musl's | ||
@@ -84,3 +84,3 @@ - Send us a pull request! Make sure to run `cargo fmt` on your code before | ||
| ``` | ||
| ```sh | ||
| cargo test | ||
@@ -92,7 +92,7 @@ ``` | ||
| ```sh | ||
| cargo test --features libm-test/test-musl-serialized | ||
| ``` | ||
| cargo test --features musl-reference-tests | ||
| ``` | ||
| Note that you may need to pass `--release` to Cargo if there are errors related | ||
| to integer overflow. |
+10
-9
@@ -39,14 +39,15 @@ # `libm` | ||
| Licensed under either of | ||
| Usage is licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or | ||
| http://opensource.org/licenses/MIT). | ||
| - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or | ||
| http://www.apache.org/licenses/LICENSE-2.0) | ||
| - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
| at your option. | ||
| ### Contribution | ||
| Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the | ||
| work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any | ||
| additional terms or conditions. | ||
| Contributions are licensed under both the MIT license and the Apache License, | ||
| Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or | ||
| http://www.apache.org/licenses/LICENSE-2.0). Unless you explicitly state | ||
| otherwise, any contribution intentionally submitted for inclusion in the work | ||
| by you, as defined in the Apache-2.0 license, shall be dual licensed as | ||
| mentioned, without any additional terms or conditions. | ||
| See `LICENSE.txt` for full details. |
+9
-14
| //! libm in pure Rust | ||
| #![deny(warnings)] | ||
| #![no_std] | ||
| #![cfg_attr(all(feature = "unstable"), feature(core_intrinsics))] | ||
| #![allow(clippy::unreadable_literal)] | ||
| #![cfg_attr(feature = "unstable", allow(internal_features))] | ||
| #![cfg_attr(feature = "unstable", feature(core_intrinsics))] | ||
| #![allow(clippy::assign_op_pattern)] | ||
| #![allow(clippy::deprecated_cfg_attr)] | ||
| #![allow(clippy::eq_op)] | ||
| #![allow(clippy::float_cmp)] | ||
| #![allow(clippy::int_plus_one)] | ||
| #![allow(clippy::many_single_char_names)] | ||
| #![allow(clippy::mixed_case_hex_literals)] | ||
| #![allow(clippy::needless_return)] | ||
| #![allow(clippy::int_plus_one)] | ||
| #![allow(clippy::deprecated_cfg_attr)] | ||
| #![allow(clippy::mixed_case_hex_literals)] | ||
| #![allow(clippy::float_cmp)] | ||
| #![allow(clippy::eq_op)] | ||
| #![allow(clippy::assign_op_pattern)] | ||
| #![allow(clippy::unreadable_literal)] | ||
@@ -55,6 +55,1 @@ mod libm_helper; | ||
| } | ||
| // PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 | ||
| #[cfg(not(target_arch = "powerpc64"))] | ||
| #[cfg(all(test, feature = "musl-reference-tests"))] | ||
| include!(concat!(env!("OUT_DIR"), "/musl-tests.rs")); |
+1
-1
@@ -23,3 +23,3 @@ #![allow(unreachable_code)] | ||
| //main implementation fails with the x87 FPU used by | ||
| //debian i386, probablly due to excess precision issues. | ||
| //debian i386, probably due to excess precision issues. | ||
| //basic implementation taken from https://github.com/rust-lang/libm/issues/219 | ||
@@ -26,0 +26,0 @@ use super::fabs; |
+1
-1
@@ -31,3 +31,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ | ||
| #[cfg_attr(rustfmt, rustfmt_skip)] | ||
| #[rustfmt::skip] | ||
| static TBL: [u64; TBLSIZE * 2] = [ | ||
@@ -34,0 +34,0 @@ // exp2(z + eps) eps |
@@ -23,3 +23,3 @@ #![allow(unreachable_code)] | ||
| //main implementation fails with the x87 FPU used by | ||
| //debian i386, probablly due to excess precision issues. | ||
| //debian i386, probably due to excess precision issues. | ||
| //basic implementation taken from https://github.com/rust-lang/libm/issues/219 | ||
@@ -26,0 +26,0 @@ use super::fabs; |
+1
-1
@@ -79,3 +79,3 @@ macro_rules! force_eval { | ||
| (#[cfg($($clause:tt)*)] $e:expr) => { | ||
| #[cfg(all(feature = "unstable", $($clause)*))] | ||
| #[cfg(all(feature = "unstable", not(feature = "force-soft-floats"), $($clause)*))] | ||
| { | ||
@@ -82,0 +82,0 @@ if true { // thwart the dead code lint |
@@ -26,3 +26,3 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] | ||
| let e = ux_i.wrapping_shr(52 & 0x7ff); | ||
| let e = ux_i >> 52 & 0x7ff; | ||
| // raise overflow if ux.f is infinite and x is finite | ||
@@ -29,0 +29,0 @@ if e == 0x7ff { |
@@ -26,3 +26,3 @@ #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] | ||
| let e = ux_i.wrapping_shr(0x7f80_0000_u32); | ||
| let e = ux_i & 0x7f80_0000_u32; | ||
| // raise overflow if ux_f is infinite and x is finite | ||
@@ -29,0 +29,0 @@ if e == 0x7f80_0000_u32 { |
+1
-1
@@ -19,3 +19,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ | ||
| // where w1 has 53-24 = 29 bit trailing zeros. | ||
| // 2. Perform y*log2(x) = n+y' by simulating muti-precision | ||
| // 2. Perform y*log2(x) = n+y' by simulating multi-precision | ||
| // arithmetic, where |y'|<=0.5. | ||
@@ -22,0 +22,0 @@ // 3. Return x**y = 2**n*exp(y'*log2) |
+3
-3
@@ -95,7 +95,7 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ | ||
| } | ||
| #[cfg(target_feature = "sse2")] | ||
| #[cfg(all(target_feature = "sse2", not(feature = "force-soft-floats")))] | ||
| { | ||
| // Note: This path is unlikely since LLVM will usually have already | ||
| // optimized sqrt calls into hardware instructions if sse2 is available, | ||
| // but if someone does end up here they'll apprected the speed increase. | ||
| // but if someone does end up here they'll appreciate the speed increase. | ||
| #[cfg(target_arch = "x86")] | ||
@@ -111,3 +111,3 @@ use core::arch::x86::*; | ||
| } | ||
| #[cfg(not(target_feature = "sse2"))] | ||
| #[cfg(any(not(target_feature = "sse2"), feature = "force-soft-floats"))] | ||
| { | ||
@@ -114,0 +114,0 @@ use core::num::Wrapping; |
@@ -30,7 +30,7 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ | ||
| } | ||
| #[cfg(target_feature = "sse")] | ||
| #[cfg(all(target_feature = "sse", not(feature = "force-soft-floats")))] | ||
| { | ||
| // Note: This path is unlikely since LLVM will usually have already | ||
| // optimized sqrt calls into hardware instructions if sse is available, | ||
| // but if someone does end up here they'll apprected the speed increase. | ||
| // but if someone does end up here they'll appreciate the speed increase. | ||
| #[cfg(target_arch = "x86")] | ||
@@ -46,3 +46,3 @@ use core::arch::x86::*; | ||
| } | ||
| #[cfg(not(target_feature = "sse"))] | ||
| #[cfg(any(not(target_feature = "sse"), feature = "force-soft-floats"))] | ||
| { | ||
@@ -49,0 +49,0 @@ const TINY: f32 = 1.0e-30; |
@@ -25,3 +25,2 @@ /* | ||
| */ | ||
| extern crate core; | ||
| use super::{exp, floor, k_cos, k_sin, pow}; | ||
@@ -28,0 +27,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet