Skip to content

Commit 57ecfc6

Browse files
committed
move math foreign_items into their own file
1 parent a06fe5a commit 57ecfc6

File tree

4 files changed

+266
-232
lines changed

4 files changed

+266
-232
lines changed

src/math.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,18 +239,15 @@ where
239239

240240
// hypot(x, ±0) = abs(x), if x is not a NaN.
241241
// `_hypot` is the Windows name for this.
242-
("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() =>
243-
x.abs(),
242+
("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() => x.abs(),
244243

245244
// atan2(±0,−0) = ±π.
246245
// atan2(±0, y) = ±π for y < 0.
247246
// Must check for non NaN because `y.is_negative()` also applies to NaN.
248-
("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) =>
249-
pi.copy_sign(*x),
247+
("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) => pi.copy_sign(*x),
250248

251249
// atan2(±x,−∞) = ±π for finite x > 0.
252-
("atan2", [x, y])
253-
if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() =>
250+
("atan2", [x, y]) if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() =>
254251
pi.copy_sign(*x),
255252

256253
// atan2(x, ±0) = −π/2 for x < 0.
@@ -262,8 +259,7 @@ where
262259
(pi_over_4 * three).value.copy_sign(*x),
263260

264261
//atan2(±∞, +∞) = ±π/4
265-
("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() =>
266-
pi_over_4.copy_sign(*x),
262+
("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() => pi_over_4.copy_sign(*x),
267263

268264
// atan2(±∞, y) returns ±π/2 for finite y.
269265
("atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) =>

src/shims/foreign_items.rs

Lines changed: 14 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::io::Write;
33
use std::path::Path;
44

55
use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size};
6-
use rustc_apfloat::Float;
76
use rustc_ast::expand::allocator::alloc_error_handler_name;
87
use rustc_hir::attrs::Linkage;
98
use rustc_hir::def::DefKind;
@@ -15,7 +14,6 @@ use rustc_middle::{mir, ty};
1514
use rustc_span::Symbol;
1615
use rustc_target::callconv::FnAbi;
1716

18-
use self::helpers::{ToHost, ToSoft};
1917
use super::alloc::EvalContextExt as _;
2018
use super::backtrace::EvalContextExt as _;
2119
use crate::helpers::EvalContextExt as _;
@@ -818,225 +816,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
818816
this.write_pointer(ptr_dest, dest)?;
819817
}
820818

821-
// math functions (note that there are also intrinsics for some other functions)
822-
#[rustfmt::skip]
823-
| "cbrtf"
824-
| "coshf"
825-
| "sinhf"
826-
| "tanf"
827-
| "tanhf"
828-
| "acosf"
829-
| "asinf"
830-
| "atanf"
831-
| "log1pf"
832-
| "expm1f"
833-
| "tgammaf"
834-
| "erff"
835-
| "erfcf"
836-
=> {
837-
let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
838-
let f = this.read_scalar(f)?.to_f32()?;
839-
840-
let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
841-
// Using host floats (but it's fine, these operations do not have
842-
// guaranteed precision).
843-
let f_host = f.to_host();
844-
let res = match link_name.as_str() {
845-
"cbrtf" => f_host.cbrt(),
846-
"coshf" => f_host.cosh(),
847-
"sinhf" => f_host.sinh(),
848-
"tanf" => f_host.tan(),
849-
"tanhf" => f_host.tanh(),
850-
"acosf" => f_host.acos(),
851-
"asinf" => f_host.asin(),
852-
"atanf" => f_host.atan(),
853-
"log1pf" => f_host.ln_1p(),
854-
"expm1f" => f_host.exp_m1(),
855-
"tgammaf" => f_host.gamma(),
856-
"erff" => f_host.erf(),
857-
"erfcf" => f_host.erfc(),
858-
_ => bug!(),
859-
};
860-
let res = res.to_soft();
861-
// Apply a relative error of 4ULP to introduce some non-determinism
862-
// simulating imprecise implementations and optimizations.
863-
let res = math::apply_random_float_error_ulp(this, res, 4);
864-
865-
// Clamp the result to the guaranteed range of this function according to the C standard,
866-
// if any.
867-
math::clamp_float_value(link_name.as_str(), res)
868-
});
869-
let res = this.adjust_nan(res, &[f]);
870-
this.write_scalar(res, dest)?;
871-
}
872-
#[rustfmt::skip]
873-
| "_hypotf"
874-
| "hypotf"
875-
| "atan2f"
876-
| "fdimf"
877-
=> {
878-
let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
879-
let f1 = this.read_scalar(f1)?.to_f32()?;
880-
let f2 = this.read_scalar(f2)?.to_f32()?;
881-
882-
let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2])
883-
.unwrap_or_else(|| {
884-
let res = match link_name.as_str() {
885-
// underscore case for windows, here and below
886-
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
887-
// Using host floats (but it's fine, these operations do not have guaranteed precision).
888-
"_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
889-
"atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
890-
#[allow(deprecated)]
891-
"fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
892-
_ => bug!(),
893-
};
894-
// Apply a relative error of 4ULP to introduce some non-determinism
895-
// simulating imprecise implementations and optimizations.
896-
let res = math::apply_random_float_error_ulp(this, res, 4);
897-
898-
// Clamp the result to the guaranteed range of this function according to the C standard,
899-
// if any.
900-
math::clamp_float_value(link_name.as_str(), res)
901-
});
902-
let res = this.adjust_nan(res, &[f1, f2]);
903-
this.write_scalar(res, dest)?;
904-
}
905-
#[rustfmt::skip]
906-
| "cbrt"
907-
| "cosh"
908-
| "sinh"
909-
| "tan"
910-
| "tanh"
911-
| "acos"
912-
| "asin"
913-
| "atan"
914-
| "log1p"
915-
| "expm1"
916-
| "tgamma"
917-
| "erf"
918-
| "erfc"
919-
=> {
920-
let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
921-
let f = this.read_scalar(f)?.to_f64()?;
922-
923-
let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| {
924-
// Using host floats (but it's fine, these operations do not have
925-
// guaranteed precision).
926-
let f_host = f.to_host();
927-
let res = match link_name.as_str() {
928-
"cbrt" => f_host.cbrt(),
929-
"cosh" => f_host.cosh(),
930-
"sinh" => f_host.sinh(),
931-
"tan" => f_host.tan(),
932-
"tanh" => f_host.tanh(),
933-
"acos" => f_host.acos(),
934-
"asin" => f_host.asin(),
935-
"atan" => f_host.atan(),
936-
"log1p" => f_host.ln_1p(),
937-
"expm1" => f_host.exp_m1(),
938-
"tgamma" => f_host.gamma(),
939-
"erf" => f_host.erf(),
940-
"erfc" => f_host.erfc(),
941-
_ => bug!(),
942-
};
943-
let res = res.to_soft();
944-
// Apply a relative error of 4ULP to introduce some non-determinism
945-
// simulating imprecise implementations and optimizations.
946-
let res = math::apply_random_float_error_ulp(this, res, 4);
947-
948-
// Clamp the result to the guaranteed range of this function according to the C standard,
949-
// if any.
950-
math::clamp_float_value(link_name.as_str(), res)
951-
});
952-
let res = this.adjust_nan(res, &[f]);
953-
this.write_scalar(res, dest)?;
954-
}
955-
#[rustfmt::skip]
956-
| "_hypot"
957-
| "hypot"
958-
| "atan2"
959-
| "fdim"
960-
=> {
961-
let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
962-
let f1 = this.read_scalar(f1)?.to_f64()?;
963-
let f2 = this.read_scalar(f2)?.to_f64()?;
964-
965-
let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| {
966-
let res = match link_name.as_str() {
967-
// underscore case for windows, here and below
968-
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
969-
// Using host floats (but it's fine, these operations do not have guaranteed precision).
970-
"_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
971-
"atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
972-
#[allow(deprecated)]
973-
"fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
974-
_ => bug!(),
975-
};
976-
// Apply a relative error of 4ULP to introduce some non-determinism
977-
// simulating imprecise implementations and optimizations.
978-
let res = math::apply_random_float_error_ulp(this, res, 4);
979-
980-
// Clamp the result to the guaranteed range of this function according to the C standard,
981-
// if any.
982-
math::clamp_float_value(link_name.as_str(), res)
983-
});
984-
let res = this.adjust_nan(res, &[f1, f2]);
985-
this.write_scalar(res, dest)?;
986-
}
987-
#[rustfmt::skip]
988-
| "_ldexp"
989-
| "ldexp"
990-
| "scalbn"
991-
=> {
992-
let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?;
993-
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
994-
let x = this.read_scalar(x)?.to_f64()?;
995-
let exp = this.read_scalar(exp)?.to_i32()?;
996-
997-
let res = x.scalbn(exp);
998-
let res = this.adjust_nan(res, &[x]);
999-
this.write_scalar(res, dest)?;
1000-
}
1001-
"lgammaf_r" => {
1002-
let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1003-
let x = this.read_scalar(x)?.to_f32()?;
1004-
let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
1005-
1006-
// Using host floats (but it's fine, these operations do not have guaranteed precision).
1007-
let (res, sign) = x.to_host().ln_gamma();
1008-
this.write_int(sign, &signp)?;
1009-
1010-
let res = res.to_soft();
1011-
// Apply a relative error of 4ULP to introduce some non-determinism
1012-
// simulating imprecise implementations and optimizations.
1013-
let res = math::apply_random_float_error_ulp(this, res, 4);
1014-
// Clamp the result to the guaranteed range of this function according to the C standard,
1015-
// if any.
1016-
let res = math::clamp_float_value(link_name.as_str(), res);
1017-
let res = this.adjust_nan(res, &[x]);
1018-
this.write_scalar(res, dest)?;
1019-
}
1020-
"lgamma_r" => {
1021-
let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
1022-
let x = this.read_scalar(x)?.to_f64()?;
1023-
let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
1024-
1025-
// Using host floats (but it's fine, these operations do not have guaranteed precision).
1026-
let (res, sign) = x.to_host().ln_gamma();
1027-
this.write_int(sign, &signp)?;
1028-
1029-
let res = res.to_soft();
1030-
// Apply a relative error of 4ULP to introduce some non-determinism
1031-
// simulating imprecise implementations and optimizations.
1032-
let res = math::apply_random_float_error_ulp(this, res, 4);
1033-
// Clamp the result to the guaranteed range of this function according to the C standard,
1034-
// if any.
1035-
let res = math::clamp_float_value(link_name.as_str(), res);
1036-
let res = this.adjust_nan(res, &[x]);
1037-
this.write_scalar(res, dest)?;
1038-
}
1039-
1040819
// LLVM intrinsics
1041820
"llvm.prefetch" => {
1042821
let [p, rw, loc, ty] =
@@ -1118,8 +897,18 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
1118897
}
1119898
}
1120899

1121-
// Platform-specific shims
1122-
_ =>
900+
// Fallback to shims in submodules.
901+
_ => {
902+
// Math shims
903+
#[expect(irrefutable_let_patterns)]
904+
if let res = shims::math::EvalContextExt::emulate_foreign_item_inner(
905+
this, link_name, abi, args, dest,
906+
)? && !matches!(res, EmulateItemResult::NotSupported)
907+
{
908+
return interp_ok(res);
909+
}
910+
911+
// Platform-specific shims
1123912
return match this.tcx.sess.target.os.as_ref() {
1124913
_ if this.target_os_is_unix() =>
1125914
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
@@ -1134,7 +923,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
1134923
this, link_name, abi, args, dest,
1135924
),
1136925
_ => interp_ok(EmulateItemResult::NotSupported),
1137-
},
926+
};
927+
}
1138928
};
1139929
// We only fall through to here if we did *not* hit the `_` arm above,
1140930
// i.e., if we actually emulated the function with one of the shims.

0 commit comments

Comments
 (0)