Auto merge of #118284 - RalfJung:miri, r=RalfJung

Miri subtree update
This commit is contained in:
bors 2023-11-25 15:07:16 +00:00
commit fe3038f263
64 changed files with 716 additions and 454 deletions

View File

@ -35,10 +35,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set the tag GC interval to 1 on linux
if: runner.os == 'Linux'
run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV
# Cache the global cargo directory, but NOT the local `target` directory which
# we cannot reuse anyway when the nightly changes (and it grows quite large
# over time).

View File

@ -2,6 +2,7 @@
use std::env;
use std::ffi::OsStr;
use std::fmt::Write;
use std::path::PathBuf;
use std::process::{self, Command};
@ -140,12 +141,20 @@ pub fn setup(
// Do the build.
if print_sysroot {
// Be silent.
} else if only_setup {
// We want to be explicit.
eprintln!("Preparing a sysroot for Miri (target: {target})...");
} else {
// We want to be quiet, but still let the user know that something is happening.
eprint!("Preparing a sysroot for Miri (target: {target})... ");
let mut msg = String::new();
write!(msg, "Preparing a sysroot for Miri (target: {target})").unwrap();
if verbose > 0 {
write!(msg, " in {}", sysroot_dir.display()).unwrap();
}
write!(msg, "...").unwrap();
if only_setup {
// We want to be explicit.
eprintln!("{msg}");
} else {
// We want to be quiet, but still let the user know that something is happening.
eprint!("{msg} ");
}
}
SysrootBuilder::new(&sysroot_dir, target)
.build_mode(BuildMode::Check)

View File

@ -30,16 +30,23 @@ endgroup
# Test
function run_tests {
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
else
begingroup "Testing host architecture"
fi
## ui test suite
./miri test
if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
# Host-only tests: running these on all targets is unlikely to catch more problems and would
# On the host and on Linux, also stress-test the GC.
if [ -z "${MIRI_TEST_TARGET:-}" ] || [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then
MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test
else
./miri test
fi
# Host-only tests
if [ -z "${MIRI_TEST_TARGET:-}" ]; then
# Running these on all targets is unlikely to catch more problems and would
# cost a lot of CI time.
# Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the
@ -85,10 +92,11 @@ function run_tests {
}
function run_tests_minimal {
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
if [ -n "${MIRI_TEST_TARGET:-}" ]; then
begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
else
begingroup "Testing MINIMAL host architecture: only testing $@"
echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
exit 1
fi
./miri test -- "$@"
@ -99,16 +107,22 @@ function run_tests_minimal {
endgroup
}
# host
## Main Testing Logic ##
# Host target.
run_tests
# Extra targets.
# In particular, fully cover all tier 1 targets.
case $HOST_TARGET in
x86_64-unknown-linux-gnu)
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc atomic env align
# Some targets are only partially supported.
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm

View File

@ -286,7 +286,7 @@ impl Command {
"This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
);
print!(
"To avoid that, abort now and set the `--rustc-git` flag to an existing rustc checkout. Proceed? [y/N] "
"To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
);
std::io::stdout().flush()?;
let mut answer = String::new();

View File

@ -1 +1 @@
820f06b21f8373060ff7b515715b8440a6a6c197
3668a8af1b81447c4afa1f82f60d7b94b71a549f

View File

@ -5,17 +5,18 @@ use std::time::Duration;
use log::trace;
use rustc_apfloat::ieee::{Double, Single};
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::{
self,
layout::{IntegerExt as _, LayoutOf, TyAndLayout},
IntTy, Ty, TyCtxt, UintTy,
layout::{LayoutOf, TyAndLayout},
FloatTy, IntTy, Ty, TyCtxt, UintTy,
};
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Integer, Size, Variants};
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
use rustc_target::spec::abi::Abi;
use rand::RngCore;
@ -565,10 +566,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
/// if this is not the case.
fn assert_target_os_is_unix(&self, name: &str) {
assert!(
target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
"`{name}` is only available for supported UNIX family targets",
);
assert!(self.target_os_is_unix(), "`{name}` is only available for unix targets",);
}
fn target_os_is_unix(&self) -> bool {
self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix")
}
/// Get last error variable as a place, lazily allocating thread-local storage for it if
@ -985,65 +987,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
/// Converts `f` to integer type `dest_ty` after rounding with mode `round`.
/// Converts `src` from floating point to integer type `dest_ty`
/// after rounding with mode `round`.
/// Returns `None` if `f` is NaN or out of range.
fn float_to_int_checked<F>(
fn float_to_int_checked(
&self,
f: F,
src: &ImmTy<'tcx, Provenance>,
cast_to: TyAndLayout<'tcx>,
round: rustc_apfloat::Round,
) -> Option<ImmTy<'tcx, Provenance>>
where
F: rustc_apfloat::Float + Into<Scalar<Provenance>>,
{
) -> InterpResult<'tcx, Option<ImmTy<'tcx, Provenance>>> {
let this = self.eval_context_ref();
let val = match cast_to.ty.kind() {
// Unsigned
ty::Uint(t) => {
let size = Integer::from_uint_ty(this, *t).size();
let res = f.to_u128_r(size.bits_usize(), round, &mut false);
if res.status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
return None;
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Scalar::from_uint(res.value, size)
fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
this: &MiriInterpCx<'_, 'tcx>,
src: F,
cast_to: TyAndLayout<'tcx>,
round: rustc_apfloat::Round,
) -> (Scalar<Provenance>, rustc_apfloat::Status) {
let int_size = cast_to.layout.size;
match cast_to.ty.kind() {
// Unsigned
ty::Uint(_) => {
let res = src.to_u128_r(int_size.bits_usize(), round, &mut false);
(Scalar::from_uint(res.value, int_size), res.status)
}
}
// Signed
ty::Int(t) => {
let size = Integer::from_int_ty(this, *t).size();
let res = f.to_i128_r(size.bits_usize(), round, &mut false);
if res.status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
return None;
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Scalar::from_int(res.value, size)
// Signed
ty::Int(_) => {
let res = src.to_i128_r(int_size.bits_usize(), round, &mut false);
(Scalar::from_int(res.value, int_size), res.status)
}
// Nothing else
_ =>
span_bug!(
this.cur_span(),
"attempted float-to-int conversion with non-int output type {}",
cast_to.ty,
),
}
}
let (val, status) = match src.layout.ty.kind() {
// f32
ty::Float(FloatTy::F32) =>
float_to_int_inner::<Single>(this, src.to_scalar().to_f32()?, cast_to, round),
// f64
ty::Float(FloatTy::F64) =>
float_to_int_inner::<Double>(this, src.to_scalar().to_f64()?, cast_to, round),
// Nothing else
_ =>
span_bug!(
this.cur_span(),
"attempted float-to-int conversion with non-int output type {}",
cast_to.ty,
"attempted float-to-int conversion with non-float input type {}",
src.layout.ty,
),
};
Some(ImmTy::from_scalar(val, cast_to))
if status.intersects(
rustc_apfloat::Status::INVALID_OP
| rustc_apfloat::Status::OVERFLOW
| rustc_apfloat::Status::UNDERFLOW,
) {
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
Ok(None)
} else {
// Floating point value can be represented by the integer type after rounding.
// The INEXACT flag is ignored on purpose to allow rounding.
Ok(Some(ImmTy::from_scalar(val, cast_to)))
}
}
/// Returns an integer type that is twice wide as `ty`
@ -1063,6 +1074,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => span_bug!(this.cur_span(), "unexpected type: {ty:?}"),
}
}
/// Checks that target feature `target_feature` is enabled.
///
/// If not enabled, emits an UB error that states that the feature is
/// required by `intrinsic`.
fn expect_target_feature_for_intrinsic(
&self,
intrinsic: Symbol,
target_feature: &str,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_ref();
if !this.tcx.sess.unstable_target_features.contains(&Symbol::intern(target_feature)) {
throw_ub_format!(
"attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}"
);
}
Ok(())
}
}
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@ -1143,12 +1172,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
local_crates
}
/// Helper function used inside the shims of foreign functions to check that
/// `target_os` is a supported UNIX OS.
pub fn target_os_is_unix(target_os: &str) -> bool {
matches!(target_os, "linux" | "macos" | "freebsd" | "android")
}
pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
// SIMD uses all-1 as pattern for "true". In two's complement,
// -1 has all its bits set to one and `from_int` will truncate or

View File

@ -125,7 +125,7 @@ pub use crate::machine::{
};
pub use crate::mono_hash_map::MonoHashMap;
pub use crate::operator::EvalContextExt as _;
pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs};
pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith};
pub use crate::range_map::RangeMap;
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be

View File

@ -157,15 +157,13 @@ pub struct LiveAllocs<'a, 'mir, 'tcx> {
impl LiveAllocs<'_, '_, '_> {
pub fn is_live(&self, id: AllocId) -> bool {
self.collected.contains(&id) ||
self.ecx.is_alloc_live(id)
self.collected.contains(&id) || self.ecx.is_alloc_live(id)
}
}
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
fn run_provenance_gc(&mut self) {
// We collect all tags from various parts of the interpreter, but also
let this = self.eval_context_mut();
@ -196,10 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
fn remove_unreachable_allocs(&mut self, allocs: FxHashSet<AllocId>) {
let this = self.eval_context_mut();
let allocs = LiveAllocs {
ecx: this,
collected: allocs,
};
let allocs = LiveAllocs { ecx: this, collected: allocs };
this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs);
if let Some(borrow_tracker) = &this.machine.borrow_tracker {

View File

@ -9,7 +9,6 @@ use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::Ty;
use rustc_target::abi::Size;
use crate::helpers::target_os_is_unix;
use crate::*;
/// Check whether an operation that writes to a target buffer was successful.
@ -53,16 +52,15 @@ impl<'tcx> EnvVars<'tcx> {
ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
config: &MiriConfig,
) -> InterpResult<'tcx> {
let target_os = ecx.tcx.sess.target.os.as_ref();
// Initialize the `env_vars` map.
// Skip the loop entirely if we don't want to forward anything.
if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() {
for (name, value) in &config.env {
let forward = ecx.machine.communicate()
|| config.forwarded_env_vars.iter().any(|v| **v == *name);
if forward {
let var_ptr = match target_os {
target if target_os_is_unix(target) =>
let var_ptr = match ecx.tcx.sess.target.os.as_ref() {
_ if ecx.target_os_is_unix() =>
alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?,
"windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?,
unsupported =>
@ -75,7 +73,17 @@ impl<'tcx> EnvVars<'tcx> {
}
}
}
ecx.update_environ()
// Initialize the `environ` pointer when needed.
if ecx.target_os_is_unix() {
// This is memory backing an extern static, hence `ExternStatic`, not `Env`.
let layout = ecx.machine.layouts.mut_raw_ptr;
let place = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
ecx.write_null(&place)?;
ecx.machine.env_vars.environ = Some(place);
ecx.update_environ()?;
}
Ok(())
}
pub(crate) fn cleanup<'mir>(
@ -87,9 +95,11 @@ impl<'tcx> EnvVars<'tcx> {
ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?;
}
// Deallocate environ var list.
let environ = ecx.machine.env_vars.environ.as_ref().unwrap();
let old_vars_ptr = ecx.read_pointer(environ)?;
ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
if ecx.target_os_is_unix() {
let environ = ecx.machine.env_vars.environ.as_ref().unwrap();
let old_vars_ptr = ecx.read_pointer(environ)?;
ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
}
Ok(())
}
}
@ -127,6 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let name_ptr = this.read_pointer(name_op)?;
let name = this.read_os_str_from_c_str(name_ptr)?;
this.read_environ()?;
Ok(match this.machine.env_vars.map.get(name) {
Some(var_ptr) => {
// The offset is used to strip the "{name}=" part of the string.
@ -275,7 +286,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Delete environment variable `{name}`
if let Some(var) = this.machine.env_vars.map.remove(&name) {
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
this.update_environ()?;
}
Ok(this.eval_windows("c", "TRUE"))
} else {
@ -284,7 +294,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) {
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
}
this.update_environ()?;
Ok(this.eval_windows("c", "TRUE"))
}
}
@ -431,15 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn update_environ(&mut self) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
// Deallocate the old environ list, if any.
if let Some(environ) = this.machine.env_vars.environ.as_ref() {
let old_vars_ptr = this.read_pointer(environ)?;
let environ = this.machine.env_vars.environ.as_ref().unwrap().clone();
let old_vars_ptr = this.read_pointer(&environ)?;
if !this.ptr_is_null(old_vars_ptr)? {
this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?;
} else {
// No `environ` allocated yet, let's do that.
// This is memory backing an extern static, hence `ExternStatic`, not `Env`.
let layout = this.machine.layouts.mut_raw_ptr;
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
this.machine.env_vars.environ = Some(place);
}
// Collect all the pointers to each variable in a vector.
@ -459,11 +463,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let place = this.project_field(&vars_place, idx)?;
this.write_pointer(var, &place)?;
}
this.write_pointer(vars_place.ptr(), &this.machine.env_vars.environ.clone().unwrap())?;
this.write_pointer(vars_place.ptr(), &environ)?;
Ok(())
}
/// Reads from the `environ` static.
/// We don't actually care about the result, but we care about this potentially causing a data race.
fn read_environ(&self) -> InterpResult<'tcx> {
let this = self.eval_context_ref();
let environ = this.machine.env_vars.environ.as_ref().unwrap();
let _vars_ptr = this.read_pointer(environ)?;
Ok(())
}
fn getpid(&mut self) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("getpid");

View File

@ -22,7 +22,6 @@ use rustc_target::{
};
use super::backtrace::EvalContextExt as _;
use crate::helpers::target_os_is_unix;
use crate::*;
/// Type of dynamic symbols (for `dlsym` et al)
@ -1012,9 +1011,11 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
// Note that different arguments might have different target feature requirements.
match arg {
// YIELD
1 => {
this.expect_target_feature_for_intrinsic(link_name, "v6")?;
this.yield_active_thread();
}
_ => {
@ -1058,7 +1059,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Platform-specific shims
_ =>
return match this.tcx.sess.target.os.as_ref() {
target_os if target_os_is_unix(target_os) =>
_ if this.target_os_is_unix() =>
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
this, link_name, abi, args, dest,
),

View File

@ -365,36 +365,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [val] = check_arg_count(args)?;
let val = this.read_immediate(val)?;
let res = match val.layout.ty.kind() {
ty::Float(FloatTy::F32) => {
let f = val.to_scalar().to_f32()?;
this
.float_to_int_checked(f, dest.layout, Round::TowardZero)
.ok_or_else(|| {
err_ub_format!(
"`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
dest.layout.ty
)
})?
}
ty::Float(FloatTy::F64) => {
let f = val.to_scalar().to_f64()?;
this
.float_to_int_checked(f, dest.layout, Round::TowardZero)
.ok_or_else(|| {
err_ub_format!(
"`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
dest.layout.ty
)
})?
}
_ =>
span_bug!(
this.cur_span(),
"`float_to_int_unchecked` called with non-float input type {:?}",
val.layout.ty
),
};
let res = this
.float_to_int_checked(&val, dest.layout, Round::TowardZero)?
.ok_or_else(|| {
err_ub_format!(
"`float_to_int_unchecked` intrinsic called on {val} which cannot be represented in target type `{:?}`",
dest.layout.ty
)
})?;
this.write_immediate(*res, dest)?;
}

View File

@ -447,22 +447,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
(ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
this.float_to_float_or_int(&op, dest.layout)?,
// Float-to-int in unchecked mode
(ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
let f = op.to_scalar().to_f32()?;
this.float_to_int_checked(f, dest.layout, Round::TowardZero)
(ty::Float(_), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
this.float_to_int_checked(&op, dest.layout, Round::TowardZero)?
.ok_or_else(|| {
err_ub_format!(
"`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
dest.layout.ty
)
})?
}
(ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
let f = op.to_scalar().to_f64()?;
this.float_to_int_checked(f, dest.layout, Round::TowardZero)
.ok_or_else(|| {
err_ub_format!(
"`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
"`simd_cast` intrinsic called on {op} which cannot be represented in target type `{:?}`",
dest.layout.ty
)
})?

View File

@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mut relative_clocks;
match this.tcx.sess.target.os.as_ref() {
"linux" => {
// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
"linux" | "freebsd" => {
// Linux and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
// Unix epoch, including effects which may cause time to move backwards such as NTP.
// Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
// is just specified to be "faster and less precise", so we implement both the same way.

View File

@ -1,30 +0,0 @@
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
pub fn is_dyn_sym(_name: &str) -> bool {
false
}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
#[allow(unused, clippy::match_single_binding)] // there isn't anything here yet
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Provenance>],
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
match link_name.as_str() {
_ => return Ok(EmulateForeignItemResult::NotSupported),
}
Ok(EmulateForeignItemResult::NeedsJumping)
}
}

View File

@ -1 +0,0 @@
pub mod foreign_items;

View File

@ -15,7 +15,6 @@ use shims::unix::mem::EvalContextExt as _;
use shims::unix::sync::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;
use shims::unix::android::foreign_items as android;
use shims::unix::freebsd::foreign_items as freebsd;
use shims::unix::linux::foreign_items as linux;
use shims::unix::macos::foreign_items as macos;
@ -32,11 +31,10 @@ fn is_dyn_sym(name: &str, target_os: &str) -> bool {
// Give specific OSes a chance to allow their symbols.
_ =>
match target_os {
"android" => android::is_dyn_sym(name),
"freebsd" => freebsd::is_dyn_sym(name),
"linux" => linux::is_dyn_sym(name),
"macos" => macos::is_dyn_sym(name),
target_os => panic!("unsupported Unix OS {target_os}"),
_ => false,
},
}
}
@ -163,6 +161,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"ftruncate64" => {
let [fd, length] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_i64()?;
let result = this.ftruncate64(fd, length.into())?;
this.write_scalar(result, dest)?;
}
"ftruncate" => {
let [fd, length] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
@ -696,7 +704,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
_ => {
let target_os = &*this.tcx.sess.target.os;
return match target_os {
"android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
"macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),

View File

@ -1504,16 +1504,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}
fn ftruncate64(
&mut self,
fd_op: &OpTy<'tcx, Provenance>,
length_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let fd = this.read_scalar(fd_op)?.to_i32()?;
let length = this.read_scalar(length_op)?.to_i64()?;
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`ftruncate64`", reject_with)?;

View File

@ -72,13 +72,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(result, dest)?;
}
"ftruncate" => {
let [fd, length] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// macOS is 64bit-only, so this is ftruncate64
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"realpath$DARWIN_EXTSN" => {
let [path, resolved_path] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

View File

@ -5,7 +5,6 @@ mod mem;
mod sync;
mod thread;
mod android;
mod freebsd;
mod linux;
mod macos;

View File

@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "aes")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.aesni.").unwrap();

View File

@ -1,4 +1,4 @@
use rustc_middle::mir;
use rustc_middle::{mir, ty};
use rustc_span::Symbol;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
@ -119,53 +119,32 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
}
}
/// Floating point comparison operation
///
/// <https://www.felixcloutier.com/x86/cmpss>
/// <https://www.felixcloutier.com/x86/cmpps>
/// <https://www.felixcloutier.com/x86/cmpsd>
/// <https://www.felixcloutier.com/x86/cmppd>
#[derive(Copy, Clone)]
enum FloatCmpOp {
Eq,
Lt,
Le,
Unord,
Neq,
/// Not less-than
Nlt,
/// Not less-or-equal
Nle,
/// Ordered, i.e. neither of them is NaN
Ord,
}
impl FloatCmpOp {
/// Convert from the `imm` argument used to specify the comparison
/// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
fn from_intrinsic_imm(imm: i8, intrinsic: &str) -> InterpResult<'_, Self> {
match imm {
0 => Ok(Self::Eq),
1 => Ok(Self::Lt),
2 => Ok(Self::Le),
3 => Ok(Self::Unord),
4 => Ok(Self::Neq),
5 => Ok(Self::Nlt),
6 => Ok(Self::Nle),
7 => Ok(Self::Ord),
imm => {
throw_unsup_format!("invalid `imm` parameter of {intrinsic}: {imm}");
}
}
}
}
#[derive(Copy, Clone)]
enum FloatBinOp {
/// Arithmetic operation
Arith(mir::BinOp),
/// Comparison
Cmp(FloatCmpOp),
///
/// The semantics of this operator is a case distinction: we compare the two operands,
/// and then we return one of the four booleans `gt`, `lt`, `eq`, `unord` depending on
/// which class they fall into.
///
/// AVX supports all 16 combinations, SSE only a subset
///
/// <https://www.felixcloutier.com/x86/cmpss>
/// <https://www.felixcloutier.com/x86/cmpps>
/// <https://www.felixcloutier.com/x86/cmpsd>
/// <https://www.felixcloutier.com/x86/cmppd>
Cmp {
/// Result when lhs < rhs
gt: bool,
/// Result when lhs > rhs
lt: bool,
/// Result when lhs == rhs
eq: bool,
/// Result when lhs is NaN or rhs is NaN
unord: bool,
},
/// Minimum value (with SSE semantics)
///
/// <https://www.felixcloutier.com/x86/minss>
@ -182,6 +161,51 @@ enum FloatBinOp {
Max,
}
impl FloatBinOp {
/// Convert from the `imm` argument used to specify the comparison
/// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
fn cmp_from_imm<'tcx>(
this: &crate::MiriInterpCx<'_, 'tcx>,
imm: i8,
intrinsic: Symbol,
) -> InterpResult<'tcx, Self> {
// Only bits 0..=4 are used, remaining should be zero.
if imm & !0b1_1111 != 0 {
throw_unsup_format!("invalid `imm` parameter of {intrinsic}: 0x{imm:x}");
}
// Bit 4 specifies whether the operation is quiet or signaling, which
// we do not care in Miri.
// Bits 0..=2 specifies the operation.
// `gt` indicates the result to be returned when the LHS is strictly
// greater than the RHS, and so on.
let (gt, lt, eq, mut unord) = match imm & 0b111 {
// Equal
0x0 => (false, false, true, false),
// Less-than
0x1 => (false, true, false, false),
// Less-or-equal
0x2 => (false, true, true, false),
// Unordered (either is NaN)
0x3 => (false, false, false, true),
// Not equal
0x4 => (true, true, false, true),
// Not less-than
0x5 => (true, false, true, true),
// Not less-or-equal
0x6 => (true, false, false, true),
// Ordered (neither is NaN)
0x7 => (true, true, true, false),
_ => unreachable!(),
};
// When bit 3 is 1 (only possible in AVX), unord is toggled.
if imm & 0b1000 != 0 {
this.expect_target_feature_for_intrinsic(intrinsic, "avx")?;
unord = !unord;
}
Ok(Self::Cmp { gt, lt, eq, unord })
}
}
/// Performs `which` scalar operation on `left` and `right` and returns
/// the result.
fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
@ -195,20 +219,15 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
let res = this.wrapping_binary_op(which, left, right)?;
Ok(res.to_scalar())
}
FloatBinOp::Cmp(which) => {
FloatBinOp::Cmp { gt, lt, eq, unord } => {
let left = left.to_scalar().to_float::<F>()?;
let right = right.to_scalar().to_float::<F>()?;
// FIXME: Make sure that these operations match the semantics
// of cmpps/cmpss/cmppd/cmpsd
let res = match which {
FloatCmpOp::Eq => left == right,
FloatCmpOp::Lt => left < right,
FloatCmpOp::Le => left <= right,
FloatCmpOp::Unord => left.is_nan() || right.is_nan(),
FloatCmpOp::Neq => left != right,
FloatCmpOp::Nlt => !(left < right),
FloatCmpOp::Nle => !(left <= right),
FloatCmpOp::Ord => !left.is_nan() && !right.is_nan(),
let res = match left.partial_cmp(&right) {
None => unord,
Some(std::cmp::Ordering::Less) => lt,
Some(std::cmp::Ordering::Equal) => eq,
Some(std::cmp::Ordering::Greater) => gt,
};
Ok(bool_to_simd_element(res, Size::from_bits(F::BITS)))
}
@ -312,6 +331,43 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
Ok(())
}
/// Converts each element of `op` from floating point to signed integer.
///
/// When the input value is NaN or out of range, fall back to minimum value.
///
/// If `op` has more elements than `dest`, extra elements are ignored. If `op`
/// has less elements than `dest`, the rest is filled with zeros.
fn convert_float_to_int<'tcx>(
this: &mut crate::MiriInterpCx<'_, 'tcx>,
op: &OpTy<'tcx, Provenance>,
rnd: rustc_apfloat::Round,
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ()> {
let (op, op_len) = this.operand_to_simd(op)?;
let (dest, dest_len) = this.place_to_simd(dest)?;
// Output must be *signed* integers.
assert!(matches!(dest.layout.field(this, 0).ty.kind(), ty::Int(_)));
for i in 0..op_len.min(dest_len) {
let op = this.read_immediate(&this.project_index(&op, i)?)?;
let dest = this.project_index(&dest, i)?;
let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
// Fallback to minimum acording to SSE/AVX semantics.
ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
});
this.write_immediate(*res, &dest)?;
}
// Fill remainder with zeros
for i in op_len..dest_len {
let dest = this.project_index(&dest, i)?;
this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
}
Ok(())
}
/// Horizontaly performs `which` operation on adjacent values of
/// `left` and `right` SIMD vectors and stores the result in `dest`.
fn horizontal_bin_op<'tcx>(

View File

@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi;
use rand::Rng as _;
use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp};
use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
@ -21,6 +21,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap();
// All these intrinsics operate on 128-bit (f32x4) SIMD vectors unless stated otherwise.
@ -95,33 +96,37 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
unary_op_ps(this, which, op, dest)?;
}
// Used to implement the _mm_cmp_ss function.
// Used to implement the _mm_cmp*_ss functions.
// Performs a comparison operation on the first component of `left`
// and `right`, returning 0 if false or `u32::MAX` if true. The remaining
// components are copied from `left`.
// _mm_cmp_ss is actually an AVX function where the operation is specified
// by a const parameter.
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions
// with hard-coded operations.
"cmp.ss" => {
let [left, right, imm] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
this.read_scalar(imm)?.to_i8()?,
"llvm.x86.sse.cmp.ss",
)?);
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
bin_op_simd_float_first::<Single>(this, which, left, right, dest)?;
}
// Used to implement the _mm_cmp_ps function.
// Used to implement the _mm_cmp*_ps functions.
// Performs a comparison operation on each component of `left`
// and `right`. For each component, returns 0 if false or u32::MAX
// if true.
// _mm_cmp_ps is actually an AVX function where the operation is specified
// by a const parameter.
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions
// with hard-coded operations.
"cmp.ps" => {
let [left, right, imm] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
this.read_scalar(imm)?.to_i8()?,
"llvm.x86.sse.cmp.ps",
)?);
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
bin_op_simd_float_all::<Single>(this, which, left, right, dest)?;
}
@ -163,7 +168,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let (op, _) = this.operand_to_simd(op)?;
let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f32()?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
@ -175,7 +180,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
_ => unreachable!(),
};
let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
// Fallback to minimum acording to SSE semantics.
ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
});

View File

@ -4,7 +4,7 @@ use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use super::{bin_op_simd_float_all, bin_op_simd_float_first, FloatBinOp, FloatCmpOp};
use super::{bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int, FloatBinOp};
use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
@ -20,6 +20,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse2")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap();
@ -259,37 +260,42 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_scalar(Scalar::from_u64(res), &dest)?;
}
}
// Used to implement the _mm_cvtps_epi32 and _mm_cvttps_epi32 functions.
// Converts packed f32 to packed i32.
"cvtps2dq" | "cvttps2dq" => {
// Used to implement the _mm_cvtps_epi32, _mm_cvttps_epi32, _mm_cvtpd_epi32
// and _mm_cvttpd_epi32 functions.
// Converts packed f32/f64 to packed i32.
"cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let (op, op_len) = this.operand_to_simd(op)?;
let (dest, dest_len) = this.place_to_simd(dest)?;
assert_eq!(dest_len, op_len);
let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
match unprefixed_name {
"cvtps2dq" | "cvttps2dq" => {
// f32x4 to i32x4 conversion
assert_eq!(op_len, 4);
assert_eq!(dest_len, op_len);
}
"cvtpd2dq" | "cvttpd2dq" => {
// f64x2 to i32x4 conversion
// the last two values are filled with zeros
assert_eq!(op_len, 2);
assert_eq!(dest_len, 4);
}
_ => unreachable!(),
}
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
// https://www.felixcloutier.com/x86/cvtps2dq
"cvtps2dq" => rustc_apfloat::Round::NearestTiesToEven,
// https://www.felixcloutier.com/x86/cvtpd2dq
"cvtps2dq" | "cvtpd2dq" => rustc_apfloat::Round::NearestTiesToEven,
// always truncate
// https://www.felixcloutier.com/x86/cvttps2dq
"cvttps2dq" => rustc_apfloat::Round::TowardZero,
// https://www.felixcloutier.com/x86/cvttpd2dq
"cvttps2dq" | "cvttpd2dq" => rustc_apfloat::Round::TowardZero,
_ => unreachable!(),
};
for i in 0..dest_len {
let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f32()?;
let dest = this.project_index(&dest, i)?;
let res =
this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
// Fallback to minimum acording to SSE2 semantics.
ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
});
this.write_immediate(*res, &dest)?;
}
convert_float_to_int(this, op, rnd, dest)?;
}
// Used to implement the _mm_packs_epi16 function.
// Converts two 16-bit integer vectors to a single 8-bit integer
@ -461,18 +467,20 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
this.write_scalar(res, &dest)?;
}
}
// Used to implement the _mm_cmp*_sd function.
// Used to implement the _mm_cmp*_sd functions.
// Performs a comparison operation on the first component of `left`
// and `right`, returning 0 if false or `u64::MAX` if true. The remaining
// components are copied from `left`.
// _mm_cmp_sd is actually an AVX function where the operation is specified
// by a const parameter.
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions
// with hard-coded operations.
"cmp.sd" => {
let [left, right, imm] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
this.read_scalar(imm)?.to_i8()?,
"llvm.x86.sse2.cmp.sd",
)?);
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
bin_op_simd_float_first::<Double>(this, which, left, right, dest)?;
}
@ -480,14 +488,16 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
// Performs a comparison operation on each component of `left`
// and `right`. For each component, returns 0 if false or `u64::MAX`
// if true.
// _mm_cmp_pd is actually an AVX function where the operation is specified
// by a const parameter.
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions
// with hard-coded operations.
"cmp.pd" => {
let [left, right, imm] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let which = FloatBinOp::Cmp(FloatCmpOp::from_intrinsic_imm(
this.read_scalar(imm)?.to_i8()?,
"llvm.x86.sse2.cmp.pd",
)?);
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
bin_op_simd_float_all::<Double>(this, which, left, right, dest)?;
}
@ -522,45 +532,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
};
this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
}
// Used to implement the _mm_cvtpd_epi32 and _mm_cvttpd_epi32 functions.
// Converts packed f64 to packed i32.
"cvtpd2dq" | "cvttpd2dq" => {
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let (op, op_len) = this.operand_to_simd(op)?;
let (dest, dest_len) = this.place_to_simd(dest)?;
// op is f64x2, dest is i32x4
assert_eq!(op_len, 2);
assert_eq!(dest_len, 4);
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
// https://www.felixcloutier.com/x86/cvtpd2dq
"cvtpd2dq" => rustc_apfloat::Round::NearestTiesToEven,
// always truncate
// https://www.felixcloutier.com/x86/cvttpd2dq
"cvttpd2dq" => rustc_apfloat::Round::TowardZero,
_ => unreachable!(),
};
for i in 0..op_len {
let op = this.read_scalar(&this.project_index(&op, i)?)?.to_f64()?;
let dest = this.project_index(&dest, i)?;
let res =
this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
// Fallback to minimum acording to SSE2 semantics.
ImmTy::from_int(i32::MIN, this.machine.layouts.i32)
});
this.write_immediate(*res, &dest)?;
}
// Fill the remaining with zeros
for i in op_len..dest_len {
let dest = this.project_index(&dest, i)?;
this.write_scalar(Scalar::from_i32(0), &dest)?;
}
}
// Use to implement the _mm_cvtsd_si32, _mm_cvttsd_si32,
// _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
// Converts the first component of `op` from f64 to i32/i64.
@ -568,7 +539,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let (op, _) = this.operand_to_simd(op)?;
let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f64()?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
@ -580,7 +551,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
_ => unreachable!(),
};
let res = this.float_to_int_checked(op, dest.layout, rnd).unwrap_or_else(|| {
let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
// Fallback to minimum acording to SSE semantics.
ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
});

View File

@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse3")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse3.").unwrap();

View File

@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse41.").unwrap();
@ -199,7 +200,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
Scalar::from_u16(min_index.try_into().unwrap()),
&this.project_index(&dest, 1)?,
)?;
// Fill remaining with zeros
// Fill remainder with zeros
for i in 2..dest_len {
this.write_scalar(Scalar::from_u16(0), &this.project_index(&dest, i)?)?;
}

View File

@ -18,6 +18,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
dest: &PlaceTy<'tcx, Provenance>,
) -> InterpResult<'tcx, EmulateForeignItemResult> {
let this = self.eval_context_mut();
this.expect_target_feature_for_intrinsic(link_name, "ssse3")?;
// Prefix should have already been checked.
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.ssse3.").unwrap();

View File

@ -0,0 +1,17 @@
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
//@ignore-target-windows: No libc on Windows
use std::env;
use std::thread;
fn main() {
let t = thread::spawn(|| unsafe {
// Access the environment in another thread without taking the env lock.
// This represents some C code that queries the environment.
libc::getenv(b"TZ\0".as_ptr().cast()); //~ERROR: Data race detected
});
// Meanwhile, the main thread uses the "safe" Rust env accessor.
env::set_var("MY_RUST_VAR", "Ferris");
t.join().unwrap();
}

View File

@ -0,0 +1,20 @@
error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here
--> $DIR/env-set_var-data-race.rs:LL:CC
|
LL | libc::getenv(b"TZ/0".as_ptr().cast());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `main` and (2) non-atomic read on thread `<unnamed>` at ALLOC. (2) just happened here
|
help: and (1) occurred earlier here
--> $DIR/env-set_var-data-race.rs:LL:CC
|
LL | env::set_var("MY_RUST_VAR", "Ferris");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE (of the first span):
= note: inside closure at $DIR/env-set_var-data-race.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
--> $DIR/float_to_int_32_inf1.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, i32>(f32::INFINITY);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
--> $DIR/float_to_int_32_infneg1.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, i32>(f32::NEG_INFINITY);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
--> $DIR/float_to_int_32_nan.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, u32>(f32::NAN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
--> $DIR/float_to_int_32_nanneg.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, u32>(-f32::NAN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32`
--> $DIR/float_to_int_32_neg.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, u32>(-1.000000001f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1f32 which cannot be represented in target type `u32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32`
--> $DIR/float_to_int_32_too_big1.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, i32>(2147483648.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9f32 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32`
--> $DIR/float_to_int_32_too_big2.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, u32>((u32::MAX - 127) as f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9f32 which cannot be represented in target type `u32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32`
--> $DIR/float_to_int_32_too_small1.rs:LL:CC
|
LL | float_to_int_unchecked::<f32, i32>(-2147483904.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9f32 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
--> $DIR/float_to_int_64_inf1.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u128>(f64::INFINITY);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
--> $DIR/float_to_int_64_infneg1.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u128>(f64::NEG_INFINITY);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
--> $DIR/float_to_int_64_infneg2.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i128>(f64::NEG_INFINITY);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
--> $DIR/float_to_int_64_nan.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u32>(f64::NAN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.0000000000000999 which cannot be represented in target type `u128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128`
--> $DIR/float_to_int_64_neg.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u128>(-1.0000000000001f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.0000000000000999 which cannot be represented in target type `u128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.0000000000000999f64 which cannot be represented in target type `u128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32`
--> $DIR/float_to_int_64_too_big1.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i32>(2147483648.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648f64 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64`
--> $DIR/float_to_int_64_too_big2.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i64>(9223372036854775808.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18f64 which cannot be represented in target type `i64`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64`
--> $DIR/float_to_int_64_too_big3.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u64>(18446744073709551616.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19f64 which cannot be represented in target type `u64`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128`
--> $DIR/float_to_int_64_too_big4.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u128>(u128::MAX as f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38f64 which cannot be represented in target type `u128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128`
--> $DIR/float_to_int_64_too_big5.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i128>(240282366920938463463374607431768211455.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38f64 which cannot be represented in target type `i128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128`
--> $DIR/float_to_int_64_too_big6.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, u128>(f64::MAX);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308f64 which cannot be represented in target type `u128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128`
--> $DIR/float_to_int_64_too_big7.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i128>(f64::MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308f64 which cannot be represented in target type `i128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32`
--> $DIR/float_to_int_64_too_small1.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i32>(-2147483649.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649f64 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64`
--> $DIR/float_to_int_64_too_small2.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i64>(-9223372036854777856.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18f64 which cannot be represented in target type `i64`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128`
error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128`
--> $DIR/float_to_int_64_too_small3.rs:LL:CC
|
LL | float_to_int_unchecked::<f64, i128>(-240282366920938463463374607431768211455.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38f64 which cannot be represented in target type `i128`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: `simd_cast` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32`
error: Undefined Behavior: `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32`
--> $DIR/simd-float-to-int.rs:LL:CC
|
LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_cast` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_cast` intrinsic called on 3.40282347E+38f32 which cannot be represented in target type `i32`
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -0,0 +1,42 @@
// Ignore everything except x86 and x86_64
// Any new targets that are added to CI should be ignored here.
// We cannot use `cfg`-based tricks here since the output would be
// different for non-x86 targets.
//@ignore-target-aarch64
//@ignore-target-arm
//@ignore-target-avr
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
// Explicitly disable SSE4.1 because it is enabled by default on macOS
//@compile-flags: -C target-feature=-sse4.1
#![feature(link_llvm_intrinsics, simd_ffi)]
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
fn main() {
assert!(is_x86_feature_detected!("sse"));
assert!(!is_x86_feature_detected!("sse4.1"));
unsafe {
// Pass, since SSE is enabled
addss(_mm_setzero_ps(), _mm_setzero_ps());
// Fail, since SSE4.1 is not enabled
dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0);
//~^ ERROR: Undefined Behavior: attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
}
}
#[allow(improper_ctypes)]
extern "C" {
#[link_name = "llvm.x86.sse.add.ss"]
fn addss(a: __m128, b: __m128) -> __m128;
#[link_name = "llvm.x86.sse41.dpps"]
fn dpps(a: __m128, b: __m128, imm8: u8) -> __m128;
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
--> $DIR/intrinsic_target_feature.rs:LL:CC
|
LL | dpps(_mm_setzero_ps(), _mm_setzero_ps(), 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to call intrinsic `llvm.x86.sse41.dpps` that requires missing target feature sse4.1
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at $DIR/intrinsic_target_feature.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View File

@ -2,15 +2,13 @@
//@ignore-target-windows: No libc on Windows
use std::ffi::CStr;
use std::ffi::CString;
use std::thread;
fn main() {
unsafe {
thread::spawn(|| {
// Access the environment in another thread without taking the env lock
let k = CString::new("MIRI_ENV_VAR_TEST".as_bytes()).unwrap();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let s = libc::getenv("MIRI_ENV_VAR_TEST\0".as_ptr().cast());
if s.is_null() {
panic!("null");
}
@ -19,5 +17,6 @@ fn main() {
thread::yield_now();
// After the main thread exits, env vars will be cleaned up -- but because we have not *joined*
// the other thread, those accesses technically race with those in the other thread.
// We don't want to emit an error here, though.
}
}

View File

@ -1,4 +1,5 @@
//@ignore-target-windows: no libc on Windows
//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0`
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"

View File

@ -23,6 +23,7 @@ fn main() {
test_file_open_unix_extra_third_arg();
#[cfg(target_os = "linux")]
test_o_tmpfile_flag();
test_posix_mkstemp();
}
/// Prepare: compute filename and make sure the file does not exist.
@ -151,3 +152,45 @@ fn test_o_tmpfile_flag() {
.raw_os_error(),
);
}
fn test_posix_mkstemp() {
use std::ffi::OsStr;
use std::os::unix::io::FromRawFd;
use std::path::Path;
let valid_template = "fooXXXXXX";
// C needs to own this as `mkstemp(3)` says:
// "Since it will be modified, `template` must not be a string constant, but
// should be declared as a character array."
// There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`.
let ptr = CString::new(valid_template).unwrap().into_raw();
let fd = unsafe { libc::mkstemp(ptr) };
// Take ownership back in Rust to not leak memory.
let slice = unsafe { CString::from_raw(ptr) };
assert!(fd > 0);
let osstr = OsStr::from_bytes(slice.to_bytes());
let path: &Path = osstr.as_ref();
let name = path.file_name().unwrap().to_string_lossy();
assert!(name.ne("fooXXXXXX"));
assert!(name.starts_with("foo"));
assert_eq!(name.len(), 9);
assert_eq!(
name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::<Vec<char>>().len(),
6
);
let file = unsafe { File::from_raw_fd(fd) };
assert!(file.set_len(0).is_ok());
let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"];
for t in invalid_templates {
let ptr = CString::new(t).unwrap().into_raw();
let fd = unsafe { libc::mkstemp(ptr) };
let _ = unsafe { CString::from_raw(ptr) };
// "On error, -1 is returned, and errno is set to
// indicate the error"
assert_eq!(fd, -1);
let e = std::io::Error::last_os_error();
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
}
}

View File

@ -172,14 +172,13 @@ fn test_thread_local_errno() {
}
/// Tests whether clock support exists at all
#[cfg(not(target_os = "freebsd"))]
fn test_clocks() {
let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
assert_eq!(is_error, 0);
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
assert_eq!(is_error, 0);
#[cfg(target_os = "linux")]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
{
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
assert_eq!(is_error, 0);
@ -238,51 +237,6 @@ fn test_isatty() {
}
}
#[cfg(not(target_os = "freebsd"))]
fn test_posix_mkstemp() {
use std::ffi::CString;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::FromRawFd;
use std::path::Path;
let valid_template = "fooXXXXXX";
// C needs to own this as `mkstemp(3)` says:
// "Since it will be modified, `template` must not be a string constant, but
// should be declared as a character array."
// There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`.
let ptr = CString::new(valid_template).unwrap().into_raw();
let fd = unsafe { libc::mkstemp(ptr) };
// Take ownership back in Rust to not leak memory.
let slice = unsafe { CString::from_raw(ptr) };
assert!(fd > 0);
let osstr = OsStr::from_bytes(slice.to_bytes());
let path: &Path = osstr.as_ref();
let name = path.file_name().unwrap().to_string_lossy();
assert!(name.ne("fooXXXXXX"));
assert!(name.starts_with("foo"));
assert_eq!(name.len(), 9);
assert_eq!(
name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::<Vec<char>>().len(),
6
);
let file = unsafe { File::from_raw_fd(fd) };
assert!(file.set_len(0).is_ok());
let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"];
for t in invalid_templates {
let ptr = CString::new(t).unwrap().into_raw();
let fd = unsafe { libc::mkstemp(ptr) };
let _ = unsafe { CString::from_raw(ptr) };
// "On error, -1 is returned, and errno is set to
// indicate the error"
assert_eq!(fd, -1);
let e = std::io::Error::last_os_error();
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput);
}
}
fn test_memcpy() {
unsafe {
let src = [1i8, 2, 3];
@ -406,9 +360,6 @@ fn test_reallocarray() {
fn main() {
test_posix_gettimeofday();
#[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
test_posix_mkstemp();
test_posix_realpath_alloc();
test_posix_realpath_noalloc();
test_posix_realpath_errors();
@ -417,7 +368,6 @@ fn main() {
test_isatty();
#[cfg(not(target_os = "freebsd"))] // FIXME we should support this on FreeBSD as well
test_clocks();
test_dlsym();

View File

@ -1,5 +1,5 @@
// Ignore everything except x86 and x86_64
// Any additional target are added to CI should be ignored here
// Any new targets that are added to CI should be ignored here.
// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
//@ignore-target-aarch64
//@ignore-target-arm

View File

@ -0,0 +1,162 @@
// Ignore everything except x86 and x86_64
// Any new targets that are added to CI should be ignored here.
// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
//@ignore-target-aarch64
//@ignore-target-arm
//@ignore-target-avr
//@ignore-target-s390x
//@ignore-target-thumbv7em
//@ignore-target-wasm32
//@compile-flags: -C target-feature=+avx
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
use std::mem::transmute;
fn main() {
assert!(is_x86_feature_detected!("avx"));
unsafe {
test_avx();
}
}
#[target_feature(enable = "avx")]
unsafe fn test_avx() {
fn expected_cmp<F: PartialOrd>(imm: i32, lhs: F, rhs: F, if_t: F, if_f: F) -> F {
let res = match imm {
_CMP_EQ_OQ => lhs == rhs,
_CMP_LT_OS => lhs < rhs,
_CMP_LE_OS => lhs <= rhs,
_CMP_UNORD_Q => lhs.partial_cmp(&rhs).is_none(),
_CMP_NEQ_UQ => lhs != rhs,
_CMP_NLT_UQ => !(lhs < rhs),
_CMP_NLE_UQ => !(lhs <= rhs),
_CMP_ORD_Q => lhs.partial_cmp(&rhs).is_some(),
_CMP_EQ_UQ => lhs == rhs || lhs.partial_cmp(&rhs).is_none(),
_CMP_NGE_US => !(lhs >= rhs),
_CMP_NGT_US => !(lhs > rhs),
_CMP_FALSE_OQ => false,
_CMP_NEQ_OQ => lhs != rhs && lhs.partial_cmp(&rhs).is_some(),
_CMP_GE_OS => lhs >= rhs,
_CMP_GT_OS => lhs > rhs,
_CMP_TRUE_US => true,
_ => unreachable!(),
};
if res { if_t } else { if_f }
}
fn expected_cmp_f32(imm: i32, lhs: f32, rhs: f32) -> f32 {
expected_cmp(imm, lhs, rhs, f32::from_bits(u32::MAX), 0.0)
}
fn expected_cmp_f64(imm: i32, lhs: f64, rhs: f64) -> f64 {
expected_cmp(imm, lhs, rhs, f64::from_bits(u64::MAX), 0.0)
}
#[target_feature(enable = "avx")]
unsafe fn test_mm_cmp_ss<const IMM: i32>() {
let values = [
(1.0, 1.0),
(0.0, 1.0),
(1.0, 0.0),
(f32::NAN, 0.0),
(0.0, f32::NAN),
(f32::NAN, f32::NAN),
];
for (lhs, rhs) in values {
let a = _mm_setr_ps(lhs, 2.0, 3.0, 4.0);
let b = _mm_setr_ps(rhs, 5.0, 6.0, 7.0);
let r: [u32; 4] = transmute(_mm_cmp_ss::<IMM>(a, b));
let e: [u32; 4] =
transmute(_mm_setr_ps(expected_cmp_f32(IMM, lhs, rhs), 2.0, 3.0, 4.0));
assert_eq!(r, e);
}
}
#[target_feature(enable = "avx")]
unsafe fn test_mm_cmp_ps<const IMM: i32>() {
let values = [
(1.0, 1.0),
(0.0, 1.0),
(1.0, 0.0),
(f32::NAN, 0.0),
(0.0, f32::NAN),
(f32::NAN, f32::NAN),
];
for (lhs, rhs) in values {
let a = _mm_set1_ps(lhs);
let b = _mm_set1_ps(rhs);
let r: [u32; 4] = transmute(_mm_cmp_ps::<IMM>(a, b));
let e: [u32; 4] = transmute(_mm_set1_ps(expected_cmp_f32(IMM, lhs, rhs)));
assert_eq!(r, e);
}
}
#[target_feature(enable = "avx")]
unsafe fn test_mm_cmp_sd<const IMM: i32>() {
let values = [
(1.0, 1.0),
(0.0, 1.0),
(1.0, 0.0),
(f64::NAN, 0.0),
(0.0, f64::NAN),
(f64::NAN, f64::NAN),
];
for (lhs, rhs) in values {
let a = _mm_setr_pd(lhs, 2.0);
let b = _mm_setr_pd(rhs, 3.0);
let r: [u64; 2] = transmute(_mm_cmp_sd::<IMM>(a, b));
let e: [u64; 2] = transmute(_mm_setr_pd(expected_cmp_f64(IMM, lhs, rhs), 2.0));
assert_eq!(r, e);
}
}
#[target_feature(enable = "avx")]
unsafe fn test_mm_cmp_pd<const IMM: i32>() {
let values = [
(1.0, 1.0),
(0.0, 1.0),
(1.0, 0.0),
(f64::NAN, 0.0),
(0.0, f64::NAN),
(f64::NAN, f64::NAN),
];
for (lhs, rhs) in values {
let a = _mm_set1_pd(lhs);
let b = _mm_set1_pd(rhs);
let r: [u64; 2] = transmute(_mm_cmp_pd::<IMM>(a, b));
let e: [u64; 2] = transmute(_mm_set1_pd(expected_cmp_f64(IMM, lhs, rhs)));
assert_eq!(r, e);
}
}
#[target_feature(enable = "avx")]
unsafe fn test_cmp<const IMM: i32>() {
test_mm_cmp_ss::<IMM>();
test_mm_cmp_ps::<IMM>();
test_mm_cmp_sd::<IMM>();
test_mm_cmp_pd::<IMM>();
}
test_cmp::<_CMP_EQ_OQ>();
test_cmp::<_CMP_LT_OS>();
test_cmp::<_CMP_LE_OS>();
test_cmp::<_CMP_UNORD_Q>();
test_cmp::<_CMP_NEQ_UQ>();
test_cmp::<_CMP_NLT_UQ>();
test_cmp::<_CMP_NLE_UQ>();
test_cmp::<_CMP_ORD_Q>();
test_cmp::<_CMP_EQ_UQ>();
test_cmp::<_CMP_NGE_US>();
test_cmp::<_CMP_NGT_US>();
test_cmp::<_CMP_FALSE_OQ>();
test_cmp::<_CMP_NEQ_OQ>();
test_cmp::<_CMP_GE_OS>();
test_cmp::<_CMP_GT_OS>();
test_cmp::<_CMP_TRUE_US>();
}

View File

@ -1,5 +1,5 @@
// Ignore everything except x86 and x86_64
// Any additional target are added to CI should be ignored here
// Any new targets that are added to CI should be ignored here.
// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
//@ignore-target-aarch64
//@ignore-target-arm

View File

@ -1,5 +1,5 @@
// Ignore everything except x86 and x86_64
// Any additional target are added to CI should be ignored here
// Any new targets that are added to CI should be ignored here.
// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
//@ignore-target-aarch64
//@ignore-target-arm

View File

@ -1,5 +1,5 @@
// Ignore everything except x86 and x86_64
// Any additional target are added to CI should be ignored here
// Any new targets that are added to CI should be ignored here.
// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
//@ignore-target-aarch64
//@ignore-target-arm

View File

@ -7,12 +7,10 @@ mod macros;
mod fs;
mod miri_extern;
pub use fs::*;
pub use miri_extern::*;
pub use self::fs::*;
pub use self::miri_extern::*;
pub fn run_provenance_gc() {
// SAFETY: No preconditions. The GC is fine to run at any time.
unsafe {
miri_run_provenance_gc()
}
unsafe { miri_run_provenance_gc() }
}