Auto merge of #151749 - JonathanBrouwer:rollup-IRCTaVD, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - rust-lang/rust#151161 (std: move time implementations to `sys`) - rust-lang/rust#151694 (more `proc_macro` bridge cleanups) - rust-lang/rust#151711 (stdarch subtree update) - rust-lang/rust#150557 (Don't try to evaluate const blocks during constant promotion)
This commit is contained in:
commit
e96bb7e44f
73 changed files with 8194 additions and 7734 deletions
|
|
@ -458,13 +458,11 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl server::Types for Rustc<'_, '_> {
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
type TokenStream = TokenStream;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_const_eval::check_consts::{ConstCx, qualifs};
|
|||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
|
|
@ -329,6 +330,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
if let TempState::Defined { location: loc, .. } = self.temps[local]
|
||||
&& let Left(statement) = self.body.stmt_at(loc)
|
||||
&& let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign()
|
||||
&& self.should_evaluate_for_promotion_checks(c.const_)
|
||||
&& let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.typing_env)
|
||||
// Determine the type of the thing we are indexing.
|
||||
&& let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind()
|
||||
|
|
@ -484,7 +486,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
let sz = lhs_ty.primitive_size(self.tcx);
|
||||
// Integer division: the RHS must be a non-zero const.
|
||||
let rhs_val = match rhs {
|
||||
Operand::Constant(c) => {
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(c.const_) =>
|
||||
{
|
||||
c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -502,9 +506,14 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// The RHS is -1 or unknown, so we have to be careful.
|
||||
// But is the LHS int::MIN?
|
||||
let lhs_val = match lhs {
|
||||
Operand::Constant(c) => c
|
||||
.const_
|
||||
.try_eval_scalar_int(self.tcx, self.typing_env),
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(
|
||||
c.const_,
|
||||
) =>
|
||||
{
|
||||
c.const_
|
||||
.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let lhs_min = sz.signed_int_min();
|
||||
|
|
@ -683,6 +692,28 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// This passed all checks, so let's accept.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Can we try to evaluate a given constant at this point in compilation? Attempting to evaluate
|
||||
/// a const block before borrow-checking will result in a query cycle (#150464).
|
||||
fn should_evaluate_for_promotion_checks(&self, constant: Const<'tcx>) -> bool {
|
||||
match constant {
|
||||
// `Const::Ty` is always a `ConstKind::Param` right now and that can never be turned
|
||||
// into a mir value for promotion
|
||||
// FIXME(mgca): do we want uses of type_const to be normalized during promotion?
|
||||
Const::Ty(..) => false,
|
||||
Const::Val(..) => true,
|
||||
// Evaluating a MIR constant requires borrow-checking it. For inline consts, as of
|
||||
// #138499, this means borrow-checking its typeck root. Since borrow-checking the
|
||||
// typeck root requires promoting its constants, trying to evaluate an inline const here
|
||||
// will result in a query cycle. To avoid the cycle, we can't evaluate const blocks yet.
|
||||
// Other kinds of unevaluated's can cause query cycles too when they arise from
|
||||
// self-reference in user code; e.g. evaluating a constant can require evaluating a
|
||||
// const function that uses that constant, again requiring evaluation of the constant.
|
||||
// However, this form of cycle renders both the constant and function unusable in
|
||||
// general, so we don't need to special-case it here.
|
||||
Const::Unevaluated(uc, _) => self.tcx.def_kind(uc.def) != DefKind::InlineConst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_candidates(
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(target_feature_inline_always)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(transparent_unions)]
|
||||
#![feature(try_blocks)]
|
||||
|
|
|
|||
|
|
@ -30,19 +30,19 @@ impl Drop for TokenStream {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
mem::ManuallyDrop::new(self).handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for TokenStream {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
TokenStream { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
|
|
@ -56,23 +56,17 @@ impl !Send for Span {}
|
|||
impl !Sync for Span {}
|
||||
|
||||
impl<S> Encode<S> for Span {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for Span {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Span { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) generate these impls by pattern-matching on the
|
||||
// names of methods - also could use the presence of `fn drop`
|
||||
// to distinguish between 'owned and 'interned, above.
|
||||
// Alternatively, special "modes" could be listed of types in with_api
|
||||
// instead of pattern matching on methods, here and in server decl.
|
||||
|
||||
impl Clone for TokenStream {
|
||||
fn clone(&self) -> Self {
|
||||
Methods::ts_clone(self)
|
||||
|
|
@ -104,10 +98,7 @@ pub(crate) use super::symbol::Symbol;
|
|||
|
||||
macro_rules! define_client_side {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
impl Methods {
|
||||
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
|
||||
|
|
@ -115,7 +106,7 @@ macro_rules! define_client_side {
|
|||
let mut buf = bridge.cached_buffer.take();
|
||||
|
||||
buf.clear();
|
||||
api_tags::Method::$method.encode(&mut buf, &mut ());
|
||||
ApiTags::$method.encode(&mut buf, &mut ());
|
||||
$($arg.encode(&mut buf, &mut ());)*
|
||||
|
||||
buf = bridge.dispatch.call(buf);
|
||||
|
|
@ -130,7 +121,7 @@ macro_rules! define_client_side {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(self, self, define_client_side);
|
||||
with_api!(self, define_client_side);
|
||||
|
||||
struct Bridge<'a> {
|
||||
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
|
||||
|
|
|
|||
|
|
@ -13,92 +13,76 @@ use std::ops::{Bound, Range};
|
|||
use std::sync::Once;
|
||||
use std::{fmt, marker, mem, panic, thread};
|
||||
|
||||
use crate::{Delimiter, Level, Spacing};
|
||||
use crate::{Delimiter, Level};
|
||||
|
||||
/// Higher-order macro describing the server RPC API, allowing automatic
|
||||
/// generation of type-safe Rust APIs, both client-side and server-side.
|
||||
///
|
||||
/// `with_api!(MySelf, my_self, my_macro)` expands to:
|
||||
/// `with_api!(MySelf, my_macro)` expands to:
|
||||
/// ```rust,ignore (pseudo-code)
|
||||
/// my_macro! {
|
||||
/// Methods {
|
||||
/// // ...
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// // ...
|
||||
/// fn lit_span(my_self: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// },
|
||||
/// Literal,
|
||||
/// Span,
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// fn lit_span(lit: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(lit: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The first two arguments serve to customize the arguments names
|
||||
/// and argument/return types, to enable several different usecases:
|
||||
///
|
||||
/// If `my_self` is just `self`, then each `fn` signature can be used
|
||||
/// as-is for a method. If it's anything else (`self_` in practice),
|
||||
/// then the signatures don't have a special `self` argument, and
|
||||
/// can, therefore, have a different one introduced.
|
||||
/// The first argument serves to customize the argument/return types,
|
||||
/// to enable several different usecases:
|
||||
///
|
||||
/// If `MySelf` is just `Self`, then the types are only valid inside
|
||||
/// a trait or a trait impl, where the trait has associated types
|
||||
/// for each of the API types. If non-associated types are desired,
|
||||
/// a module name (`self` in practice) can be used instead of `Self`.
|
||||
macro_rules! with_api {
|
||||
($S:ident, $self:ident, $m:ident) => {
|
||||
($S:ident, $m:ident) => {
|
||||
$m! {
|
||||
Methods {
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
},
|
||||
TokenStream,
|
||||
Span,
|
||||
Symbol,
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -129,7 +113,7 @@ mod symbol;
|
|||
|
||||
use buffer::Buffer;
|
||||
pub use rpc::PanicMessage;
|
||||
use rpc::{Decode, Encode, Reader, Writer};
|
||||
use rpc::{Decode, Encode};
|
||||
|
||||
/// Configuration for establishing an active connection between a server and a
|
||||
/// client. The server creates the bridge config (`run_server` in `server.rs`),
|
||||
|
|
@ -151,26 +135,18 @@ pub struct BridgeConfig<'a> {
|
|||
impl !Send for BridgeConfig<'_> {}
|
||||
impl !Sync for BridgeConfig<'_> {}
|
||||
|
||||
#[forbid(unsafe_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
mod api_tags {
|
||||
use super::rpc::{Decode, Encode, Reader, Writer};
|
||||
|
||||
macro_rules! declare_tags {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
pub(super) enum Method {
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum Method { $($method),* });
|
||||
macro_rules! declare_tags {
|
||||
(
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(super) enum ApiTags {
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum ApiTags { $($method),* });
|
||||
}
|
||||
with_api!(self, self, declare_tags);
|
||||
}
|
||||
with_api!(self, declare_tags);
|
||||
|
||||
/// Helper to wrap associated types to allow trait impl dispatch.
|
||||
/// That is, normally a pair of impls for `T::Foo` and `T::Bar`
|
||||
|
|
@ -179,11 +155,6 @@ mod api_tags {
|
|||
trait Mark {
|
||||
type Unmarked;
|
||||
fn mark(unmarked: Self::Unmarked) -> Self;
|
||||
}
|
||||
|
||||
/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details).
|
||||
trait Unmark {
|
||||
type Unmarked;
|
||||
fn unmark(self) -> Self::Unmarked;
|
||||
}
|
||||
|
||||
|
|
@ -198,25 +169,19 @@ impl<T, M> Mark for Marked<T, M> {
|
|||
fn mark(unmarked: Self::Unmarked) -> Self {
|
||||
Marked { value: unmarked, _marker: marker::PhantomData }
|
||||
}
|
||||
}
|
||||
impl<T, M> Unmark for Marked<T, M> {
|
||||
type Unmarked = T;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
impl<'a, T, M> Unmark for &'a Marked<T, M> {
|
||||
impl<'a, T, M> Mark for &'a Marked<T, M> {
|
||||
type Unmarked = &'a T;
|
||||
fn mark(_: Self::Unmarked) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
impl<'a, T, M> Unmark for &'a mut Marked<T, M> {
|
||||
type Unmarked = &'a mut T;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
&mut self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Mark> Mark for Vec<T> {
|
||||
type Unmarked = Vec<T::Unmarked>;
|
||||
|
|
@ -224,9 +189,6 @@ impl<T: Mark> Mark for Vec<T> {
|
|||
// Should be a no-op due to std's in-place collect optimizations.
|
||||
unmarked.into_iter().map(T::mark).collect()
|
||||
}
|
||||
}
|
||||
impl<T: Unmark> Unmark for Vec<T> {
|
||||
type Unmarked = Vec<T::Unmarked>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
// Should be a no-op due to std's in-place collect optimizations.
|
||||
self.into_iter().map(T::unmark).collect()
|
||||
|
|
@ -241,9 +203,6 @@ macro_rules! mark_noop {
|
|||
fn mark(unmarked: Self::Unmarked) -> Self {
|
||||
unmarked
|
||||
}
|
||||
}
|
||||
impl Unmark for $ty {
|
||||
type Unmarked = Self;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
self
|
||||
}
|
||||
|
|
@ -254,8 +213,6 @@ macro_rules! mark_noop {
|
|||
mark_noop! {
|
||||
(),
|
||||
bool,
|
||||
char,
|
||||
&'_ [u8],
|
||||
&'_ str,
|
||||
String,
|
||||
u8,
|
||||
|
|
@ -263,7 +220,6 @@ mark_noop! {
|
|||
Delimiter,
|
||||
LitKind,
|
||||
Level,
|
||||
Spacing,
|
||||
}
|
||||
|
||||
rpc_encode_decode!(
|
||||
|
|
@ -282,12 +238,6 @@ rpc_encode_decode!(
|
|||
Help,
|
||||
}
|
||||
);
|
||||
rpc_encode_decode!(
|
||||
enum Spacing {
|
||||
Alone,
|
||||
Joint,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum LitKind {
|
||||
|
|
@ -333,13 +283,9 @@ macro_rules! mark_compound {
|
|||
$($field: Mark::mark(unmarked.$field)),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($T: Unmark),+> Unmark for $name <$($T),+> {
|
||||
type Unmarked = $name <$($T::Unmarked),+>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
$name {
|
||||
$($field: Unmark::unmark(self.$field)),*
|
||||
$($field: Mark::unmark(self.$field)),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,14 +300,10 @@ macro_rules! mark_compound {
|
|||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($T: Unmark),+> Unmark for $name <$($T),+> {
|
||||
type Unmarked = $name <$($T::Unmarked),+>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
match self {
|
||||
$($name::$variant $(($field))? => {
|
||||
$name::$variant $((Unmark::unmark($field)))?
|
||||
$name::$variant $((Mark::unmark($field)))?
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,28 +4,26 @@ use std::any::Any;
|
|||
use std::io::Write;
|
||||
use std::num::NonZero;
|
||||
|
||||
pub(super) type Writer = super::buffer::Buffer;
|
||||
use super::buffer::Buffer;
|
||||
|
||||
pub(super) trait Encode<S>: Sized {
|
||||
fn encode(self, w: &mut Writer, s: &mut S);
|
||||
fn encode(self, w: &mut Buffer, s: &mut S);
|
||||
}
|
||||
|
||||
pub(super) type Reader<'a> = &'a [u8];
|
||||
|
||||
pub(super) trait Decode<'a, 's, S>: Sized {
|
||||
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
|
||||
fn decode(r: &mut &'a [u8], s: &'s mut S) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! rpc_encode_decode {
|
||||
(le $ty:ty) => {
|
||||
impl<S> Encode<S> for $ty {
|
||||
fn encode(self, w: &mut Writer, _: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, _: &mut S) {
|
||||
w.extend_from_array(&self.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for $ty {
|
||||
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], _: &mut S) -> Self {
|
||||
const N: usize = size_of::<$ty>();
|
||||
|
||||
let mut bytes = [0; N];
|
||||
|
|
@ -38,7 +36,7 @@ macro_rules! rpc_encode_decode {
|
|||
};
|
||||
(struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => {
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
$(self.$field.encode(w, s);)*
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +44,7 @@ macro_rules! rpc_encode_decode {
|
|||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
$name {
|
||||
$($field: Decode::decode(r, s)),*
|
||||
}
|
||||
|
|
@ -55,10 +53,12 @@ macro_rules! rpc_encode_decode {
|
|||
};
|
||||
(enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u8)]
|
||||
enum Tag { $($variant),* }
|
||||
|
||||
match self {
|
||||
$($name::$variant $(($field))* => {
|
||||
|
|
@ -72,10 +72,10 @@ macro_rules! rpc_encode_decode {
|
|||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(non_upper_case_globals, non_camel_case_types)]
|
||||
mod tag {
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
|
||||
|
|
@ -95,21 +95,21 @@ macro_rules! rpc_encode_decode {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for () {
|
||||
fn encode(self, _: &mut Writer, _: &mut S) {}
|
||||
fn encode(self, _: &mut Buffer, _: &mut S) {}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for () {
|
||||
fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
|
||||
fn decode(_: &mut &[u8], _: &mut S) -> Self {}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for u8 {
|
||||
fn encode(self, w: &mut Writer, _: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, _: &mut S) {
|
||||
w.push(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for u8 {
|
||||
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], _: &mut S) -> Self {
|
||||
let x = r[0];
|
||||
*r = &r[1..];
|
||||
x
|
||||
|
|
@ -120,13 +120,13 @@ rpc_encode_decode!(le u32);
|
|||
rpc_encode_decode!(le usize);
|
||||
|
||||
impl<S> Encode<S> for bool {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
(self as u8).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for bool {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
match u8::decode(r, s) {
|
||||
0 => false,
|
||||
1 => true,
|
||||
|
|
@ -135,32 +135,20 @@ impl<S> Decode<'_, '_, S> for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for char {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
(self as u32).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for char {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
char::from_u32(u32::decode(r, s)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for NonZero<u32> {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.get().encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for NonZero<u32> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Self::new(u32::decode(r, s)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.0.encode(w, s);
|
||||
self.1.encode(w, s);
|
||||
}
|
||||
|
|
@ -169,53 +157,42 @@ impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
|
|||
impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S>
|
||||
for (A, B)
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
(Decode::decode(r, s), Decode::decode(r, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &[u8] {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.len().encode(w, s);
|
||||
w.write_all(self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Decode<'a, '_, S> for &'a [u8] {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let xs = &r[..len];
|
||||
*r = &r[len..];
|
||||
xs
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &str {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.as_bytes().encode(w, s);
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
let bytes = self.as_bytes();
|
||||
bytes.len().encode(w, s);
|
||||
w.write_all(bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Decode<'a, '_, S> for &'a str {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let xs = &r[..len];
|
||||
*r = &r[len..];
|
||||
str::from_utf8(xs).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for String {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self[..].encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for String {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
<&str>::decode(r, s).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T: Encode<S>> Encode<S> for Vec<T> {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.len().encode(w, s);
|
||||
for x in self {
|
||||
x.encode(w, s);
|
||||
|
|
@ -224,7 +201,7 @@ impl<S, T: Encode<S>> Encode<S> for Vec<T> {
|
|||
}
|
||||
|
||||
impl<'a, S, T: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for Vec<T> {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let mut vec = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
|
|
@ -278,13 +255,13 @@ impl PanicMessage {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for PanicMessage {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.as_str().encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for PanicMessage {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
match Option::<String>::decode(r, s) {
|
||||
Some(s) => PanicMessage::String(s),
|
||||
None => PanicMessage::Unknown,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use std::marker::PhantomData;
|
|||
|
||||
use super::*;
|
||||
|
||||
pub(super) struct HandleStore<S: Types> {
|
||||
token_stream: handle::OwnedStore<Marked<S::TokenStream, client::TokenStream>>,
|
||||
span: handle::InternedStore<Marked<S::Span, client::Span>>,
|
||||
pub(super) struct HandleStore<S: Server> {
|
||||
token_stream: handle::OwnedStore<MarkedTokenStream<S>>,
|
||||
span: handle::InternedStore<MarkedSpan<S>>,
|
||||
}
|
||||
|
||||
impl<S: Types> HandleStore<S> {
|
||||
impl<S: Server> HandleStore<S> {
|
||||
fn new(handle_counters: &'static client::HandleCounters) -> Self {
|
||||
HandleStore {
|
||||
token_stream: handle::OwnedStore::new(&handle_counters.token_stream),
|
||||
|
|
@ -19,52 +19,54 @@ impl<S: Types> HandleStore<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
pub(super) type MarkedTokenStream<S> = Marked<<S as Server>::TokenStream, client::TokenStream>;
|
||||
pub(super) type MarkedSpan<S> = Marked<<S as Server>::Span, client::Span>;
|
||||
pub(super) type MarkedSymbol<S> = Marked<<S as Server>::Symbol, client::Symbol>;
|
||||
|
||||
impl<S: Server> Encode<HandleStore<S>> for MarkedTokenStream<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut HandleStore<S>) {
|
||||
s.token_stream.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
impl<S: Server> Decode<'_, '_, HandleStore<S>> for MarkedTokenStream<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut HandleStore<S>) -> Self {
|
||||
s.token_stream.take(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: Types> Decode<'_, 's, HandleStore<S>>
|
||||
for &'s Marked<S::TokenStream, client::TokenStream>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<S>) -> Self {
|
||||
impl<'s, S: Server> Decode<'_, 's, HandleStore<S>> for &'s MarkedTokenStream<S> {
|
||||
fn decode(r: &mut &[u8], s: &'s mut HandleStore<S>) -> Self {
|
||||
&s.token_stream[handle::Handle::decode(r, &mut ())]
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
impl<S: Server> Encode<HandleStore<S>> for MarkedSpan<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut HandleStore<S>) {
|
||||
s.span.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
impl<S: Server> Decode<'_, '_, HandleStore<S>> for MarkedSpan<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut HandleStore<S>) -> Self {
|
||||
s.span.copy(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Types {
|
||||
type TokenStream: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
struct Dispatcher<S: Server> {
|
||||
handle_store: HandleStore<S>,
|
||||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! declare_server_traits {
|
||||
macro_rules! define_server_dispatcher_impl {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
pub trait Server: Types {
|
||||
pub trait Server {
|
||||
type TokenStream: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span>;
|
||||
|
||||
/// Intern a symbol received from RPC
|
||||
|
|
@ -75,39 +77,28 @@ macro_rules! declare_server_traits {
|
|||
|
||||
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)*
|
||||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, declare_server_traits);
|
||||
|
||||
struct Dispatcher<S: Types> {
|
||||
handle_store: HandleStore<S>,
|
||||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! define_dispatcher_impl {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
|
||||
pub trait DispatcherTrait {
|
||||
// HACK(eddyb) these are here to allow `Self::$name` to work below.
|
||||
$(type $name;)*
|
||||
type TokenStream;
|
||||
type Span;
|
||||
type Symbol;
|
||||
|
||||
fn dispatch(&mut self, buf: Buffer) -> Buffer;
|
||||
}
|
||||
|
||||
impl<S: Server> DispatcherTrait for Dispatcher<S> {
|
||||
$(type $name = Marked<S::$name, client::$name>;)*
|
||||
type TokenStream = MarkedTokenStream<S>;
|
||||
type Span = MarkedSpan<S>;
|
||||
type Symbol = MarkedSymbol<S>;
|
||||
|
||||
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
|
||||
let Dispatcher { handle_store, server } = self;
|
||||
|
||||
let mut reader = &buf[..];
|
||||
match api_tags::Method::decode(&mut reader, &mut ()) {
|
||||
$(api_tags::Method::$method => {
|
||||
match ApiTags::decode(&mut reader, &mut ()) {
|
||||
$(ApiTags::$method => {
|
||||
let mut call_method = || {
|
||||
$(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)*
|
||||
let r = server.$method($($arg),*);
|
||||
|
|
@ -136,7 +127,7 @@ macro_rules! define_dispatcher_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, define_dispatcher_impl);
|
||||
with_api!(Self, define_server_dispatcher_impl);
|
||||
|
||||
pub trait ExecutionStrategy {
|
||||
fn run_bridge_and_client(
|
||||
|
|
@ -303,7 +294,7 @@ fn run_server<
|
|||
let globals = dispatcher.server.globals();
|
||||
|
||||
let mut buf = Buffer::new();
|
||||
(<ExpnGlobals<Marked<S::Span, client::Span>> as Mark>::mark(globals), input)
|
||||
(<ExpnGlobals<MarkedSpan<S>> as Mark>::mark(globals), input)
|
||||
.encode(&mut buf, &mut dispatcher.handle_store);
|
||||
|
||||
buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics);
|
||||
|
|
@ -328,13 +319,11 @@ impl client::Client<crate::TokenStream, crate::TokenStream> {
|
|||
strategy,
|
||||
handle_counters,
|
||||
server,
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
<MarkedTokenStream<S>>::mark(input),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
.map(|s| <Option<MarkedTokenStream<S>>>::unmark(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -356,15 +345,10 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream
|
|||
strategy,
|
||||
handle_counters,
|
||||
server,
|
||||
(
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input2),
|
||||
),
|
||||
(<MarkedTokenStream<S>>::mark(input), <MarkedTokenStream<S>>::mark(input2)),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
.map(|s| <Option<MarkedTokenStream<S>>>::unmark(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,25 +94,25 @@ impl fmt::Display for Symbol {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for Symbol {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.with(|sym| sym.encode(w, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore<S>) -> Self {
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<S>> for server::MarkedSymbol<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut server::HandleStore<S>) -> Self {
|
||||
Mark::mark(S::intern_symbol(<&str>::decode(r, s)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Encode<server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn encode(self, w: &mut Writer, s: &mut server::HandleStore<S>) {
|
||||
impl<S: server::Server> Encode<server::HandleStore<S>> for server::MarkedSymbol<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut server::HandleStore<S>) {
|
||||
S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for Symbol {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Symbol::new(<&str>::decode(r, s))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(target_feature_inline_always)]
|
||||
#![feature(thread_local)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(try_trait_v2)]
|
||||
|
|
|
|||
|
|
@ -580,7 +580,8 @@ mod uefi_fs {
|
|||
use crate::path::Path;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sys::pal::helpers::{self, UefiBox};
|
||||
use crate::sys::time::{self, SystemTime};
|
||||
use crate::sys::pal::system_time;
|
||||
use crate::sys::time::SystemTime;
|
||||
|
||||
pub(crate) struct File {
|
||||
protocol: NonNull<file::Protocol>,
|
||||
|
|
@ -879,7 +880,7 @@ mod uefi_fs {
|
|||
/// conversion to SystemTime, we use the current time to get the timezone in such cases.
|
||||
pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option<SystemTime> {
|
||||
time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
time::system_time_internal::now().timezone
|
||||
system_time::now().timezone
|
||||
} else {
|
||||
time.timezone
|
||||
};
|
||||
|
|
@ -888,7 +889,7 @@ mod uefi_fs {
|
|||
|
||||
/// Convert to UEFI Time with the current timezone.
|
||||
pub(crate) fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time {
|
||||
let now = time::system_time_internal::now();
|
||||
let now = system_time::now();
|
||||
time.to_uefi_loose(now.timezone, now.daylight)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1822,7 +1822,7 @@ impl File {
|
|||
_ => {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
@ -2258,7 +2258,7 @@ fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Resu
|
|||
let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW };
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ pub mod stdio;
|
|||
pub mod sync;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod time;
|
||||
|
||||
// FIXME(117276): remove this, move feature implementations into individual
|
||||
// submodules.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
|
|||
use crate::net::{Shutdown, SocketAddr};
|
||||
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::time::Instant;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
pub use crate::sys::{cvt, cvt_r};
|
||||
use crate::time::Duration;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::{cmp, mem};
|
||||
|
||||
#[expect(non_camel_case_types)]
|
||||
|
|
|
|||
|
|
@ -1,35 +1,32 @@
|
|||
#![allow(dead_code)]
|
||||
use hermit_abi::{self, timespec};
|
||||
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
use super::hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME, timespec};
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::time::Duration;
|
||||
|
||||
const NSEC_PER_SEC: i32 = 1_000_000_000;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Timespec {
|
||||
t: timespec,
|
||||
pub struct Timespec {
|
||||
pub t: timespec,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
|
||||
pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
|
||||
|
||||
const MIN: Timespec = Self::new(i64::MIN, 0);
|
||||
pub const MIN: Timespec = Self::new(i64::MIN, 0);
|
||||
|
||||
const fn zero() -> Timespec {
|
||||
pub const fn zero() -> Timespec {
|
||||
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
|
||||
pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
|
||||
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC);
|
||||
// SAFETY: The assert above checks tv_nsec is within the valid range
|
||||
Timespec { t: timespec { tv_sec, tv_nsec } }
|
||||
}
|
||||
|
||||
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||
fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
|
||||
debug_assert!(a >= b);
|
||||
a.wrapping_sub(b).cast_unsigned()
|
||||
|
|
@ -57,7 +54,7 @@ impl Timespec {
|
|||
}
|
||||
}
|
||||
|
||||
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
|
||||
|
||||
// Nano calculations can't overflow because nanos are <1B which fit
|
||||
|
|
@ -70,7 +67,7 @@ impl Timespec {
|
|||
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
|
||||
}
|
||||
|
||||
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
|
||||
|
||||
// Similar to above, nanos can't overflow.
|
||||
|
|
@ -111,132 +108,3 @@ impl Hash for Timespec {
|
|||
self.t.tv_nsec.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Timespec);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
|
||||
|
||||
Instant(time)
|
||||
}
|
||||
|
||||
#[stable(feature = "time2", since = "1.8.0")]
|
||||
pub fn elapsed(&self) -> Duration {
|
||||
Instant::now() - *self
|
||||
}
|
||||
|
||||
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
||||
self.checked_duration_since(earlier).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
|
||||
self.checked_sub_instant(&earlier)
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.sub_timespec(&other.0).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
|
||||
self.0.checked_add_duration(&duration).map(Instant)
|
||||
}
|
||||
|
||||
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
|
||||
self.0.checked_sub_duration(&duration).map(Instant)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if the resulting point in time cannot be represented by the
|
||||
/// underlying data structure. See [`Instant::checked_add`] for a version without panic.
|
||||
fn add(self, other: Duration) -> Instant {
|
||||
self.checked_add(other).expect("overflow when adding duration to instant")
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Duration> for Instant {
|
||||
fn add_assign(&mut self, other: Duration) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
|
||||
fn sub(self, other: Duration) -> Instant {
|
||||
self.checked_sub(other).expect("overflow when subtracting duration from instant")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<Duration> for Instant {
|
||||
fn sub_assign(&mut self, other: Duration) {
|
||||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Instant> for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one,
|
||||
/// or zero duration if that instant is later than this one.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Previous Rust versions panicked when `other` was later than `self`. Currently this
|
||||
/// method saturates. Future versions may reintroduce the panic in some circumstances.
|
||||
/// See [Monotonicity].
|
||||
///
|
||||
/// [Monotonicity]: Instant#monotonicity
|
||||
fn sub(self, other: Instant) -> Duration {
|
||||
self.duration_since(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct SystemTime(Timespec);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime(Timespec::MAX);
|
||||
|
||||
pub const MIN: SystemTime = SystemTime(Timespec::MIN);
|
||||
|
||||
pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
|
||||
SystemTime(Timespec::new(tv_sec, tv_nsec))
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
|
||||
|
||||
SystemTime(time)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.0.sub_timespec(&other.0)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,38 +3,16 @@ use super::error::expect_success;
|
|||
use crate::mem::MaybeUninit;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(abi::SYSTIM);
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
// Safety: The provided pointer is valid
|
||||
unsafe {
|
||||
let mut out = MaybeUninit::uninit();
|
||||
expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
|
||||
Instant(out.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0).map(|ticks| {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
Duration::from_micros(ticks)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
|
||||
#[inline]
|
||||
pub fn get_tim() -> abi::SYSTIM {
|
||||
// Safety: The provided pointer is valid
|
||||
unsafe {
|
||||
let mut out = MaybeUninit::uninit();
|
||||
expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
|
||||
out.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +76,7 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -
|
|||
// a problem in practice. (`u64::MAX` μs ≈ 584942 years)
|
||||
let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
|
||||
|
||||
let start = Instant::now().0;
|
||||
let start = get_tim();
|
||||
let mut elapsed = 0;
|
||||
let mut er = abi::E_TMOUT;
|
||||
while elapsed <= ticks {
|
||||
|
|
@ -106,11 +84,8 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -
|
|||
if er != abi::E_TMOUT {
|
||||
break;
|
||||
}
|
||||
elapsed = Instant::now().0.wrapping_sub(start);
|
||||
elapsed = get_tim().wrapping_sub(start);
|
||||
}
|
||||
|
||||
er
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
pub use moto_rt::futex;
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
pub use moto_rt::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||
|
|
@ -12,7 +12,6 @@ pub mod abi;
|
|||
mod libunwind_integration;
|
||||
pub mod os;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
pub mod waitqueue;
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ pub mod itron {
|
|||
pub(crate) mod error;
|
||||
pub mod os;
|
||||
pub use self::itron::thread_parking;
|
||||
pub mod time;
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
pub mod os;
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[path = "../unix/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,5 @@
|
|||
mod common;
|
||||
#[path = "../unsupported/os.rs"]
|
||||
pub mod os;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
pub use common::*;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
pub mod helpers;
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
pub mod system_time;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
151
library/std/src/sys/pal/uefi/system_time.rs
Normal file
151
library/std/src/sys/pal/uefi/system_time.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
use r_efi::efi::{RuntimeServices, Time};
|
||||
|
||||
use super::helpers;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::time::Duration;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
|
||||
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
|
||||
const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64;
|
||||
|
||||
pub(crate) fn now() -> Time {
|
||||
let runtime_services: NonNull<RuntimeServices> =
|
||||
helpers::runtime_services().expect("Runtime services are not available");
|
||||
let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
|
||||
let r =
|
||||
unsafe { ((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut()) };
|
||||
if r.is_error() {
|
||||
panic!("time not implemented on this platform");
|
||||
}
|
||||
|
||||
unsafe { t.assume_init() }
|
||||
}
|
||||
|
||||
/// This algorithm is a modified form of the one described in the post
|
||||
/// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn from_uefi(t: &Time) -> Option<Duration> {
|
||||
if !(t.month <= 12
|
||||
&& t.month != 0
|
||||
&& t.year >= 1900
|
||||
&& t.year <= 9999
|
||||
&& t.day <= 31
|
||||
&& t.day != 0
|
||||
&& t.second < 60
|
||||
&& t.minute <= 60
|
||||
&& t.hour < 24
|
||||
&& t.nanosecond < 1_000_000_000
|
||||
&& ((t.timezone <= 1440 && t.timezone >= -1440)
|
||||
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
|
||||
|
||||
// Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
|
||||
// time.
|
||||
// Use 1 March as the start
|
||||
let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
|
||||
let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
|
||||
let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
|
||||
let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
|
||||
let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
|
||||
let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
|
||||
|
||||
let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
|
||||
+ (t.second as u64)
|
||||
+ (t.minute as u64) * SECS_IN_MINUTE
|
||||
+ (t.hour as u64) * SECS_IN_HOUR;
|
||||
|
||||
let normalized_timezone = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
-SYSTEMTIME_TIMEZONE
|
||||
} else {
|
||||
(t.timezone as i64) * SECS_IN_MINUTE as i64 - SYSTEMTIME_TIMEZONE
|
||||
};
|
||||
|
||||
// Calculate the offset from 1/1/1900 at timezone -1440 min
|
||||
let epoch = localtime_epoch.checked_add_signed(normalized_timezone).unwrap();
|
||||
|
||||
Some(Duration::new(epoch, t.nanosecond))
|
||||
}
|
||||
|
||||
/// This algorithm is a modified version of the one described in the post:
|
||||
/// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Result<Time, i16> {
|
||||
const MIN_IN_HOUR: u64 = 60;
|
||||
const MIN_IN_DAY: u64 = MIN_IN_HOUR * 24;
|
||||
|
||||
// Check timezone validity
|
||||
assert!(timezone <= 1440 && timezone >= -1440);
|
||||
|
||||
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
|
||||
let Some(secs) = dur
|
||||
.as_secs()
|
||||
.checked_add_signed(SYSTEMTIME_TIMEZONE - (timezone as i64 * SECS_IN_MINUTE as i64))
|
||||
else {
|
||||
// If the current timezone cannot be used, find the closest timezone that will allow the
|
||||
// conversion to succeed.
|
||||
let new_tz = (dur.as_secs() / SECS_IN_MINUTE) as i16
|
||||
+ (SYSTEMTIME_TIMEZONE / SECS_IN_MINUTE as i64) as i16;
|
||||
return Err(new_tz);
|
||||
};
|
||||
|
||||
let days = secs / SECS_IN_DAY;
|
||||
let remaining_secs = secs % SECS_IN_DAY;
|
||||
|
||||
let z = days + 693901;
|
||||
let era = z / 146097;
|
||||
let doe = z - (era * 146097);
|
||||
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
|
||||
let mut y = yoe + era * 400;
|
||||
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
|
||||
let mp = (5 * doy + 2) / 153;
|
||||
let d = doy - (153 * mp + 2) / 5 + 1;
|
||||
let m = if mp < 10 { mp + 3 } else { mp - 9 };
|
||||
|
||||
if m <= 2 {
|
||||
y += 1;
|
||||
}
|
||||
|
||||
let hour = (remaining_secs / SECS_IN_HOUR) as u8;
|
||||
let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
|
||||
let second = (remaining_secs % SECS_IN_MINUTE) as u8;
|
||||
|
||||
// At this point, invalid time will be greater than MAX representable time. It cannot be less
|
||||
// than minimum time since we already take care of that case above.
|
||||
if y <= 9999 {
|
||||
Ok(Time {
|
||||
year: y as u16,
|
||||
month: m as u8,
|
||||
day: d as u8,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
nanosecond: dur.subsec_nanos(),
|
||||
timezone,
|
||||
daylight,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
})
|
||||
} else {
|
||||
assert!(y == 10000);
|
||||
assert!(m == 1);
|
||||
|
||||
let delta = ((d - 1) as u64 * MIN_IN_DAY
|
||||
+ hour as u64 * MIN_IN_HOUR
|
||||
+ minute as u64
|
||||
+ if second == 0 { 0 } else { 1 }) as i16;
|
||||
let new_tz = timezone + delta;
|
||||
|
||||
assert!(new_tz <= 1440 && new_tz >= -1440);
|
||||
Err(new_tz)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
use core::num::niche_types::Nanoseconds;
|
||||
|
||||
use crate::sys::AsInner;
|
||||
use crate::io;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, io};
|
||||
|
||||
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||
|
||||
#[allow(dead_code)] // Used for pthread condvar timeouts
|
||||
pub const TIMESPEC_MAX: libc::timespec =
|
||||
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
|
||||
|
|
@ -18,60 +17,19 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
|
|||
tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SystemTime {
|
||||
pub(crate) t: Timespec,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct Timespec {
|
||||
tv_sec: i64,
|
||||
tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
|
||||
|
||||
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
|
||||
|
||||
#[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
|
||||
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.t.sub_timespec(&other.t)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
pub tv_sec: i64,
|
||||
pub tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
pub const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
|
||||
// As described below, on Apple OS, dates before epoch are represented differently.
|
||||
// This is not an issue here however, because we are using tv_sec = i64::MIN,
|
||||
// which will cause the compatibility wrapper to not be executed at all.
|
||||
const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
pub const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
|
||||
const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
|
||||
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } }
|
||||
|
|
@ -81,7 +39,7 @@ impl Timespec {
|
|||
unsafe { Self::new_unchecked(0, 0) }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
// On Apple OS, dates before epoch are represented differently than on other
|
||||
// Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
|
||||
// and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
|
||||
|
|
@ -263,98 +221,3 @@ impl __timespec64 {
|
|||
Self { tv_sec, tv_nsec, _padding: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant {
|
||||
t: Timespec,
|
||||
}
|
||||
|
||||
impl Instant {
|
||||
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||
// ment while the system is asleep. The returned value
|
||||
// is identical to the result of mach_absolute_time()
|
||||
// after the appropriate mach_timebase conversion is
|
||||
// applied.
|
||||
//
|
||||
// We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
|
||||
// `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
|
||||
// clock that all timeouts and deadlines are measured against inside
|
||||
// the kernel.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||
|
||||
pub fn now() -> Instant {
|
||||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
|
||||
Instant { t: Timespec::now(Self::CLOCK_ID) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
|
||||
)]
|
||||
pub(crate) fn into_timespec(self) -> Timespec {
|
||||
self.t
|
||||
}
|
||||
|
||||
/// Returns `self` converted into units of `mach_absolute_time`, or `None`
|
||||
/// if `self` is before the system boot time. If the conversion cannot be
|
||||
/// performed precisely, this ceils the result up to the nearest
|
||||
/// representable value.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
|
||||
#[repr(C)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
|
||||
}
|
||||
|
||||
let secs = u64::try_from(self.t.tv_sec).ok()?;
|
||||
|
||||
let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
|
||||
assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
|
||||
|
||||
// Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
|
||||
// this cannot overflow. The resulting number needs at most 94 bits.
|
||||
let nanos =
|
||||
u128::from(secs) * u128::from(NSEC_PER_SEC) + u128::from(self.t.tv_nsec.as_inner());
|
||||
// This multiplication cannot overflow since multiplying a 94-bit
|
||||
// number by a 32-bit number yields a number that needs at most
|
||||
// 126 bits.
|
||||
Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Timespec> for Instant {
|
||||
fn as_inner(&self) -> &Timespec {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Instant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Instant")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
mod common;
|
||||
pub use common::*;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[path = "../unsupported/common.rs"]
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#[path = "../unsupported/os.rs"]
|
||||
pub mod os;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
#[path = "atomics/futex.rs"]
|
||||
|
|
|
|||
|
|
@ -1,170 +1,12 @@
|
|||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::Neg;
|
||||
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::Neg;
|
||||
use crate::ptr::null;
|
||||
use crate::sys::{IntoInner, c};
|
||||
use crate::sys::pal::c;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, mem};
|
||||
|
||||
const NANOS_PER_SEC: u64 = 1_000_000_000;
|
||||
const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
|
||||
pub const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
|
||||
pub struct Instant {
|
||||
// This duration is relative to an arbitrary microsecond epoch
|
||||
// from the winapi QueryPerformanceCounter function.
|
||||
t: Duration,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SystemTime {
|
||||
t: c::FILETIME,
|
||||
}
|
||||
|
||||
const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC;
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32,
|
||||
dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32,
|
||||
},
|
||||
};
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
// High precision timing on windows operates in "Performance Counter"
|
||||
// units, as returned by the WINAPI QueryPerformanceCounter function.
|
||||
// These relate to seconds by a factor of QueryPerformanceFrequency.
|
||||
// In order to keep unit conversions out of normal interval math, we
|
||||
// measure in QPC units and immediately convert to nanoseconds.
|
||||
perf_counter::PerformanceCounterInstant::now().into()
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
// On windows there's a threshold below which we consider two timestamps
|
||||
// equivalent due to measurement error. For more details + doc link,
|
||||
// check the docs on epsilon.
|
||||
let epsilon = perf_counter::PerformanceCounterInstant::epsilon();
|
||||
if other.t > self.t && other.t - self.t <= epsilon {
|
||||
Some(Duration::new(0, 0))
|
||||
} else {
|
||||
self.t.checked_sub(other.t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add(*other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub(*other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32,
|
||||
dwHighDateTime: (i64::MAX >> 32) as u32,
|
||||
},
|
||||
};
|
||||
|
||||
pub const MIN: SystemTime =
|
||||
SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } };
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
unsafe {
|
||||
let mut t: SystemTime = mem::zeroed();
|
||||
c::GetSystemTimePreciseAsFileTime(&mut t.t);
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
fn from_intervals(intervals: i64) -> SystemTime {
|
||||
SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: intervals as u32,
|
||||
dwHighDateTime: (intervals >> 32) as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn intervals(&self) -> i64 {
|
||||
(self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
let me = self.intervals();
|
||||
let other = other.intervals();
|
||||
if me >= other {
|
||||
Ok(intervals2dur((me - other) as u64))
|
||||
} else {
|
||||
Err(intervals2dur((other - me) as u64))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
|
||||
Some(SystemTime::from_intervals(intervals))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
// Windows does not support times before 1601, hence why we don't
|
||||
// support negatives. In order to tackle this, we try to convert the
|
||||
// resulting value into an u64, which should obviously fail in the case
|
||||
// that the value is below zero.
|
||||
let intervals: u64 =
|
||||
self.intervals().checked_sub(checked_dur2intervals(other)?)?.try_into().ok()?;
|
||||
Some(SystemTime::from_intervals(intervals as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SystemTime {
|
||||
fn eq(&self, other: &SystemTime) -> bool {
|
||||
self.intervals() == other.intervals()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SystemTime {}
|
||||
|
||||
impl PartialOrd for SystemTime {
|
||||
fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SystemTime {
|
||||
fn cmp(&self, other: &SystemTime) -> Ordering {
|
||||
self.intervals().cmp(&other.intervals())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime").field("intervals", &self.intervals()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c::FILETIME> for SystemTime {
|
||||
fn from(t: c::FILETIME) -> SystemTime {
|
||||
SystemTime { t }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<c::FILETIME> for SystemTime {
|
||||
fn into_inner(self) -> c::FILETIME {
|
||||
self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SystemTime {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.intervals().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
||||
pub fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
||||
dur.as_secs()
|
||||
.checked_mul(INTERVALS_PER_SEC)?
|
||||
.checked_add(dur.subsec_nanos() as u64 / 100)?
|
||||
|
|
@ -172,43 +14,23 @@ fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
|||
.ok()
|
||||
}
|
||||
|
||||
fn intervals2dur(intervals: u64) -> Duration {
|
||||
pub fn intervals2dur(intervals: u64) -> Duration {
|
||||
Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
|
||||
}
|
||||
|
||||
mod perf_counter {
|
||||
pub mod perf_counter {
|
||||
use super::NANOS_PER_SEC;
|
||||
use crate::sync::atomic::{Atomic, AtomicU64, Ordering};
|
||||
use crate::sys::helpers::mul_div_u64;
|
||||
use crate::sys::{c, cvt};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct PerformanceCounterInstant {
|
||||
ts: i64,
|
||||
}
|
||||
impl PerformanceCounterInstant {
|
||||
pub fn now() -> Self {
|
||||
Self { ts: query() }
|
||||
}
|
||||
|
||||
// Per microsoft docs, the margin of error for cross-thread time comparisons
|
||||
// using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
|
||||
// /acquiring-high-resolution-time-stamps
|
||||
pub fn epsilon() -> Duration {
|
||||
let epsilon = NANOS_PER_SEC / (frequency() as u64);
|
||||
Duration::from_nanos(epsilon)
|
||||
}
|
||||
}
|
||||
impl From<PerformanceCounterInstant> for super::Instant {
|
||||
fn from(other: PerformanceCounterInstant) -> Self {
|
||||
let freq = frequency() as u64;
|
||||
let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq);
|
||||
Self { t: Duration::from_nanos(instant_nsec) }
|
||||
}
|
||||
pub fn now() -> i64 {
|
||||
let mut qpc_value: i64 = 0;
|
||||
cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
|
||||
qpc_value
|
||||
}
|
||||
|
||||
fn frequency() -> i64 {
|
||||
pub fn frequency() -> i64 {
|
||||
// Either the cached result of `QueryPerformanceFrequency` or `0` for
|
||||
// uninitialized. Storing this as a single `AtomicU64` allows us to use
|
||||
// `Relaxed` operations, as we are only interested in the effects on a
|
||||
|
|
@ -230,10 +52,13 @@ mod perf_counter {
|
|||
frequency
|
||||
}
|
||||
|
||||
fn query() -> i64 {
|
||||
let mut qpc_value: i64 = 0;
|
||||
cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
|
||||
qpc_value
|
||||
// Per microsoft docs, the margin of error for cross-thread time comparisons
|
||||
// using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
|
||||
// /acquiring-high-resolution-time-stamps
|
||||
pub fn epsilon() -> Duration {
|
||||
let epsilon = NANOS_PER_SEC / (frequency() as u64);
|
||||
Duration::from_nanos(epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,6 +66,7 @@ mod perf_counter {
|
|||
pub(crate) struct WaitableTimer {
|
||||
handle: c::HANDLE,
|
||||
}
|
||||
|
||||
impl WaitableTimer {
|
||||
/// Creates a high-resolution timer. Will fail before Windows 10, version 1803.
|
||||
pub fn high_resolution() -> Result<Self, ()> {
|
||||
|
|
@ -254,6 +80,7 @@ impl WaitableTimer {
|
|||
};
|
||||
if !handle.is_null() { Ok(Self { handle }) } else { Err(()) }
|
||||
}
|
||||
|
||||
pub fn set(&self, duration: Duration) -> Result<(), ()> {
|
||||
// Convert the Duration to a format similar to FILETIME.
|
||||
// Negative values are relative times whereas positive values are absolute.
|
||||
|
|
@ -262,11 +89,13 @@ impl WaitableTimer {
|
|||
let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
|
||||
if result != 0 { Ok(()) } else { Err(()) }
|
||||
}
|
||||
|
||||
pub fn wait(&self) -> Result<(), ()> {
|
||||
let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
|
||||
if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WaitableTimer {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::CloseHandle(self.handle) };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
mod common;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ pub const WORD_SIZE: usize = size_of::<u32>();
|
|||
|
||||
pub mod abi;
|
||||
pub mod os;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
use crate::io as std_io;
|
||||
|
||||
|
|
|
|||
63
library/std/src/sys/time/hermit.rs
Normal file
63
library/std/src/sys/time/hermit.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME};
|
||||
|
||||
use crate::hash::Hash;
|
||||
use crate::sys::pal::time::Timespec;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Timespec);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
|
||||
|
||||
Instant(time)
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.sub_timespec(&other.0).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct SystemTime(Timespec);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime(Timespec::MAX);
|
||||
|
||||
pub const MIN: SystemTime = SystemTime(Timespec::MIN);
|
||||
|
||||
pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
|
||||
SystemTime(Timespec::new(tv_sec, tv_nsec))
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
|
||||
|
||||
SystemTime(time)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.0.sub_timespec(&other.0)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
}
|
||||
53
library/std/src/sys/time/mod.rs
Normal file
53
library/std/src/sys/time/mod.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
cfg_select! {
|
||||
target_os = "hermit" => {
|
||||
mod hermit;
|
||||
use hermit as imp;
|
||||
}
|
||||
target_os = "motor" => {
|
||||
use moto_rt::time as imp;
|
||||
}
|
||||
all(target_vendor = "fortanix", target_env = "sgx") => {
|
||||
mod sgx;
|
||||
use sgx as imp;
|
||||
}
|
||||
target_os = "solid_asp3" => {
|
||||
mod solid;
|
||||
use solid as imp;
|
||||
}
|
||||
target_os = "uefi" => {
|
||||
mod uefi;
|
||||
use uefi as imp;
|
||||
}
|
||||
any(
|
||||
target_os = "teeos",
|
||||
target_family = "unix",
|
||||
target_os = "wasi",
|
||||
) => {
|
||||
mod unix;
|
||||
use unix as imp;
|
||||
}
|
||||
target_os = "vexos" => {
|
||||
mod vexos;
|
||||
#[expect(unused)]
|
||||
mod unsupported;
|
||||
|
||||
mod imp {
|
||||
pub use super::vexos::Instant;
|
||||
pub use super::unsupported::{SystemTime, UNIX_EPOCH};
|
||||
}
|
||||
}
|
||||
target_os = "windows" => {
|
||||
mod windows;
|
||||
use windows as imp;
|
||||
}
|
||||
target_os = "xous" => {
|
||||
mod xous;
|
||||
use xous as imp;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
}
|
||||
}
|
||||
|
||||
pub use imp::{Instant, SystemTime, UNIX_EPOCH};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use super::abi::usercalls;
|
||||
use crate::sys::pal::abi::usercalls;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
|
|
@ -1,9 +1,38 @@
|
|||
use super::abi;
|
||||
use super::error::expect_success;
|
||||
pub use super::itron::time::Instant;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::sys::pal::error::expect_success;
|
||||
use crate::sys::pal::{abi, itron};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(itron::abi::SYSTIM);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
Instant(itron::time::get_tim())
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0).map(|ticks| {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
Duration::from_micros(ticks)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct SystemTime(abi::time_t);
|
||||
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use crate::sys::pal::system_time;
|
||||
use crate::time::Duration;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Duration);
|
||||
|
||||
|
|
@ -88,7 +87,7 @@ impl SystemTime {
|
|||
.unwrap();
|
||||
|
||||
pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Option<Self> {
|
||||
match system_time_internal::from_uefi(&t) {
|
||||
match system_time::from_uefi(&t) {
|
||||
Some(x) => Some(Self(x)),
|
||||
None => None,
|
||||
}
|
||||
|
|
@ -99,12 +98,12 @@ impl SystemTime {
|
|||
timezone: i16,
|
||||
daylight: u8,
|
||||
) -> Result<r_efi::efi::Time, i16> {
|
||||
// system_time_internal::to_uefi requires a valid timezone. In case of unspecified timezone,
|
||||
// system_time::to_uefi requires a valid timezone. In case of unspecified timezone,
|
||||
// we just pass 0 since it is assumed that no timezone related adjustments are required.
|
||||
if timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
system_time_internal::to_uefi(&self.0, 0, daylight)
|
||||
system_time::to_uefi(&self.0, 0, daylight)
|
||||
} else {
|
||||
system_time_internal::to_uefi(&self.0, timezone, daylight)
|
||||
system_time::to_uefi(&self.0, timezone, daylight)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,8 +117,7 @@ impl SystemTime {
|
|||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
Self::from_uefi(system_time_internal::now())
|
||||
.expect("time incorrectly implemented on this platform")
|
||||
Self::from_uefi(system_time::now()).expect("time incorrectly implemented on this platform")
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
|
|
@ -138,169 +136,15 @@ impl SystemTime {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) mod system_time_internal {
|
||||
use r_efi::efi::{RuntimeServices, Time};
|
||||
|
||||
use super::super::helpers;
|
||||
use super::*;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr::NonNull;
|
||||
|
||||
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
|
||||
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
|
||||
const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64;
|
||||
|
||||
pub(crate) fn now() -> Time {
|
||||
let runtime_services: NonNull<RuntimeServices> =
|
||||
helpers::runtime_services().expect("Runtime services are not available");
|
||||
let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
|
||||
let r = unsafe {
|
||||
((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut())
|
||||
};
|
||||
if r.is_error() {
|
||||
panic!("time not implemented on this platform");
|
||||
}
|
||||
|
||||
unsafe { t.assume_init() }
|
||||
}
|
||||
|
||||
/// This algorithm is a modified form of the one described in the post
|
||||
/// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn from_uefi(t: &Time) -> Option<Duration> {
|
||||
if !(t.month <= 12
|
||||
&& t.month != 0
|
||||
&& t.year >= 1900
|
||||
&& t.year <= 9999
|
||||
&& t.day <= 31
|
||||
&& t.day != 0
|
||||
&& t.second < 60
|
||||
&& t.minute <= 60
|
||||
&& t.hour < 24
|
||||
&& t.nanosecond < 1_000_000_000
|
||||
&& ((t.timezone <= 1440 && t.timezone >= -1440)
|
||||
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
|
||||
|
||||
// Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
|
||||
// time.
|
||||
// Use 1 March as the start
|
||||
let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
|
||||
let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
|
||||
let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
|
||||
let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
|
||||
let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
|
||||
let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
|
||||
|
||||
let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
|
||||
+ (t.second as u64)
|
||||
+ (t.minute as u64) * SECS_IN_MINUTE
|
||||
+ (t.hour as u64) * SECS_IN_HOUR;
|
||||
|
||||
let normalized_timezone = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
-SYSTEMTIME_TIMEZONE
|
||||
} else {
|
||||
(t.timezone as i64) * SECS_IN_MINUTE as i64 - SYSTEMTIME_TIMEZONE
|
||||
};
|
||||
|
||||
// Calculate the offset from 1/1/1900 at timezone -1440 min
|
||||
let epoch = localtime_epoch.checked_add_signed(normalized_timezone).unwrap();
|
||||
|
||||
Some(Duration::new(epoch, t.nanosecond))
|
||||
}
|
||||
|
||||
/// This algorithm is a modified version of the one described in the post:
|
||||
/// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Result<Time, i16> {
|
||||
const MIN_IN_HOUR: u64 = 60;
|
||||
const MIN_IN_DAY: u64 = MIN_IN_HOUR * 24;
|
||||
|
||||
// Check timezone validity
|
||||
assert!(timezone <= 1440 && timezone >= -1440);
|
||||
|
||||
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
|
||||
let Some(secs) = dur
|
||||
.as_secs()
|
||||
.checked_add_signed(SYSTEMTIME_TIMEZONE - (timezone as i64 * SECS_IN_MINUTE as i64))
|
||||
else {
|
||||
// If the current timezone cannot be used, find the closest timezone that will allow the
|
||||
// conversion to succeed.
|
||||
let new_tz = (dur.as_secs() / SECS_IN_MINUTE) as i16
|
||||
+ (SYSTEMTIME_TIMEZONE / SECS_IN_MINUTE as i64) as i16;
|
||||
return Err(new_tz);
|
||||
};
|
||||
|
||||
let days = secs / SECS_IN_DAY;
|
||||
let remaining_secs = secs % SECS_IN_DAY;
|
||||
|
||||
let z = days + 693901;
|
||||
let era = z / 146097;
|
||||
let doe = z - (era * 146097);
|
||||
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
|
||||
let mut y = yoe + era * 400;
|
||||
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
|
||||
let mp = (5 * doy + 2) / 153;
|
||||
let d = doy - (153 * mp + 2) / 5 + 1;
|
||||
let m = if mp < 10 { mp + 3 } else { mp - 9 };
|
||||
|
||||
if m <= 2 {
|
||||
y += 1;
|
||||
}
|
||||
|
||||
let hour = (remaining_secs / SECS_IN_HOUR) as u8;
|
||||
let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
|
||||
let second = (remaining_secs % SECS_IN_MINUTE) as u8;
|
||||
|
||||
// At this point, invalid time will be greater than MAX representable time. It cannot be less
|
||||
// than minimum time since we already take care of that case above.
|
||||
if y <= 9999 {
|
||||
Ok(Time {
|
||||
year: y as u16,
|
||||
month: m as u8,
|
||||
day: d as u8,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
nanosecond: dur.subsec_nanos(),
|
||||
timezone,
|
||||
daylight,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
})
|
||||
} else {
|
||||
assert!(y == 10000);
|
||||
assert!(m == 1);
|
||||
|
||||
let delta = ((d - 1) as u64 * MIN_IN_DAY
|
||||
+ hour as u64 * MIN_IN_HOUR
|
||||
+ minute as u64
|
||||
+ if second == 0 { 0 } else { 1 }) as i16;
|
||||
let new_tz = timezone + delta;
|
||||
|
||||
assert!(new_tz <= 1440 && new_tz >= -1440);
|
||||
Err(new_tz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod instant_internal {
|
||||
mod instant_internal {
|
||||
use r_efi::protocols::timestamp;
|
||||
|
||||
use super::super::helpers;
|
||||
use super::*;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
|
||||
use crate::sys::helpers::mul_div_u64;
|
||||
use crate::sys::pal::helpers;
|
||||
|
||||
const NS_PER_SEC: u64 = 1_000_000_000;
|
||||
|
||||
141
library/std/src/sys/time/unix.rs
Normal file
141
library/std/src/sys/time/unix.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use crate::sys::AsInner;
|
||||
use crate::sys::pal::time::Timespec;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, io};
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SystemTime {
|
||||
pub(crate) t: Timespec,
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
|
||||
|
||||
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
|
||||
|
||||
#[cfg_attr(any(target_os = "horizon", target_os = "hurd", target_os = "teeos"), expect(unused))]
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
|
||||
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.t.sub_timespec(&other.t)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant {
|
||||
t: Timespec,
|
||||
}
|
||||
|
||||
impl Instant {
|
||||
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||
// ment while the system is asleep. The returned value
|
||||
// is identical to the result of mach_absolute_time()
|
||||
// after the appropriate mach_timebase conversion is
|
||||
// applied.
|
||||
//
|
||||
// We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
|
||||
// `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
|
||||
// clock that all timeouts and deadlines are measured against inside
|
||||
// the kernel.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||
|
||||
pub fn now() -> Instant {
|
||||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
|
||||
Instant { t: Timespec::now(Self::CLOCK_ID) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
|
||||
)]
|
||||
pub(crate) fn into_timespec(self) -> Timespec {
|
||||
self.t
|
||||
}
|
||||
|
||||
/// Returns `self` converted into units of `mach_absolute_time`, or `None`
|
||||
/// if `self` is before the system boot time. If the conversion cannot be
|
||||
/// performed precisely, this ceils the result up to the nearest
|
||||
/// representable value.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
|
||||
#[repr(C)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
|
||||
}
|
||||
|
||||
let secs = u64::try_from(self.t.tv_sec).ok()?;
|
||||
|
||||
let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
|
||||
assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
|
||||
|
||||
// Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
|
||||
// this cannot overflow. The resulting number needs at most 94 bits.
|
||||
let nanos = 1_000_000_000 * u128::from(secs) + u128::from(self.t.tv_nsec.as_inner());
|
||||
// This multiplication cannot overflow since multiplying a 94-bit
|
||||
// number by a 32-bit number yields a number that needs at most
|
||||
// 126 bits.
|
||||
Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Timespec> for Instant {
|
||||
fn as_inner(&self) -> &Timespec {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Instant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Instant")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,5 @@
|
|||
use crate::time::Duration;
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[path = "../unsupported/time.rs"]
|
||||
mod unsupported_time;
|
||||
pub use unsupported_time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Duration);
|
||||
|
||||
156
library/std/src/sys/time/windows.rs
Normal file
156
library/std/src/sys/time/windows.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use crate::cmp::Ordering;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::sys::helpers::mul_div_u64;
|
||||
use crate::sys::pal::time::{
|
||||
INTERVALS_PER_SEC, checked_dur2intervals, intervals2dur, perf_counter,
|
||||
};
|
||||
use crate::sys::{IntoInner, c};
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, mem};
|
||||
|
||||
const NANOS_PER_SEC: u64 = 1_000_000_000;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
|
||||
pub struct Instant {
|
||||
// This duration is relative to an arbitrary microsecond epoch
|
||||
// from the winapi QueryPerformanceCounter function.
|
||||
t: Duration,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SystemTime {
|
||||
t: c::FILETIME,
|
||||
}
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime =
|
||||
SystemTime::from_intervals(11_644_473_600 * INTERVALS_PER_SEC as i64);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
// High precision timing on windows operates in "Performance Counter"
|
||||
// units, as returned by the WINAPI QueryPerformanceCounter function.
|
||||
// These relate to seconds by a factor of QueryPerformanceFrequency.
|
||||
// In order to keep unit conversions out of normal interval math, we
|
||||
// measure in QPC units and immediately convert to nanoseconds.
|
||||
|
||||
let freq = perf_counter::frequency() as u64;
|
||||
let now = perf_counter::now();
|
||||
let instant_nsec = mul_div_u64(now as u64, NANOS_PER_SEC, freq);
|
||||
Self { t: Duration::from_nanos(instant_nsec) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
// On windows there's a threshold below which we consider two timestamps
|
||||
// equivalent due to measurement error. For more details + doc link,
|
||||
// check the docs on epsilon.
|
||||
let epsilon = perf_counter::epsilon();
|
||||
if other.t > self.t && other.t - self.t <= epsilon {
|
||||
Some(Duration::new(0, 0))
|
||||
} else {
|
||||
self.t.checked_sub(other.t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add(*other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub(*other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime::from_intervals(i64::MAX);
|
||||
pub const MIN: SystemTime = SystemTime::from_intervals(0);
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
unsafe {
|
||||
let mut t: SystemTime = mem::zeroed();
|
||||
c::GetSystemTimePreciseAsFileTime(&mut t.t);
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
const fn from_intervals(intervals: i64) -> SystemTime {
|
||||
SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: intervals as u32,
|
||||
dwHighDateTime: (intervals >> 32) as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn intervals(&self) -> i64 {
|
||||
(self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
let me = self.intervals();
|
||||
let other = other.intervals();
|
||||
if me >= other {
|
||||
Ok(intervals2dur((me - other) as u64))
|
||||
} else {
|
||||
Err(intervals2dur((other - me) as u64))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
|
||||
Some(SystemTime::from_intervals(intervals))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
// Windows does not support times before 1601, hence why we don't
|
||||
// support negatives. In order to tackle this, we try to convert the
|
||||
// resulting value into an u64, which should obviously fail in the case
|
||||
// that the value is below zero.
|
||||
let intervals: u64 =
|
||||
self.intervals().checked_sub(checked_dur2intervals(other)?)?.try_into().ok()?;
|
||||
Some(SystemTime::from_intervals(intervals as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SystemTime {
|
||||
fn eq(&self, other: &SystemTime) -> bool {
|
||||
self.intervals() == other.intervals()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SystemTime {}
|
||||
|
||||
impl PartialOrd for SystemTime {
|
||||
fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SystemTime {
|
||||
fn cmp(&self, other: &SystemTime) -> Ordering {
|
||||
self.intervals().cmp(&other.intervals())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime").field("intervals", &self.intervals()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c::FILETIME> for SystemTime {
|
||||
fn from(t: c::FILETIME) -> SystemTime {
|
||||
SystemTime { t }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<c::FILETIME> for SystemTime {
|
||||
fn into_inner(self) -> c::FILETIME {
|
||||
self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SystemTime {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.intervals().hash(state)
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ case ${TARGET} in
|
|||
export RUSTFLAGS="${RUSTFLAGS} -C llvm-args=-fast-isel=false"
|
||||
;;
|
||||
armv7-*eabihf | thumbv7-*eabihf)
|
||||
export RUSTFLAGS="${RUSTFLAGS} -Ctarget-feature=+neon"
|
||||
export RUSTFLAGS="${RUSTFLAGS} -Ctarget-feature=+neon,+fp16"
|
||||
;;
|
||||
amdgcn-*)
|
||||
export RUSTFLAGS="${RUSTFLAGS} -Ctarget-cpu=gfx1200"
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
ignore = [
|
||||
"src/simd.rs",
|
||||
]
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -13,194 +13,195 @@ use crate::core_arch::aarch64::*;
|
|||
use crate::core_arch::simd::*;
|
||||
use std::mem;
|
||||
use stdarch_test::simd_test;
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_s8() {
|
||||
fn test_vld1_s8() {
|
||||
let a: [i8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: i8x8 = transmute(vld1_s8(a[1..].as_ptr()));
|
||||
let r = unsafe { i8x8::from(vld1_s8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_s8() {
|
||||
fn test_vld1q_s8() {
|
||||
let a: [i8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let e = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
let r: i8x16 = transmute(vld1q_s8(a[1..].as_ptr()));
|
||||
let r = unsafe { i8x16::from(vld1q_s8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_s16() {
|
||||
fn test_vld1_s16() {
|
||||
let a: [i16; 5] = [0, 1, 2, 3, 4];
|
||||
let e = i16x4::new(1, 2, 3, 4);
|
||||
let r: i16x4 = transmute(vld1_s16(a[1..].as_ptr()));
|
||||
let r = unsafe { i16x4::from(vld1_s16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_s16() {
|
||||
fn test_vld1q_s16() {
|
||||
let a: [i16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: i16x8 = transmute(vld1q_s16(a[1..].as_ptr()));
|
||||
let r = unsafe { i16x8::from(vld1q_s16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_s32() {
|
||||
fn test_vld1_s32() {
|
||||
let a: [i32; 3] = [0, 1, 2];
|
||||
let e = i32x2::new(1, 2);
|
||||
let r: i32x2 = transmute(vld1_s32(a[1..].as_ptr()));
|
||||
let r = unsafe { i32x2::from(vld1_s32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_s32() {
|
||||
fn test_vld1q_s32() {
|
||||
let a: [i32; 5] = [0, 1, 2, 3, 4];
|
||||
let e = i32x4::new(1, 2, 3, 4);
|
||||
let r: i32x4 = transmute(vld1q_s32(a[1..].as_ptr()));
|
||||
let r = unsafe { i32x4::from(vld1q_s32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_s64() {
|
||||
fn test_vld1_s64() {
|
||||
let a: [i64; 2] = [0, 1];
|
||||
let e = i64x1::new(1);
|
||||
let r: i64x1 = transmute(vld1_s64(a[1..].as_ptr()));
|
||||
let r = unsafe { i64x1::from(vld1_s64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_s64() {
|
||||
fn test_vld1q_s64() {
|
||||
let a: [i64; 3] = [0, 1, 2];
|
||||
let e = i64x2::new(1, 2);
|
||||
let r: i64x2 = transmute(vld1q_s64(a[1..].as_ptr()));
|
||||
let r = unsafe { i64x2::from(vld1q_s64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_u8() {
|
||||
fn test_vld1_u8() {
|
||||
let a: [u8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: u8x8 = transmute(vld1_u8(a[1..].as_ptr()));
|
||||
let r = unsafe { u8x8::from(vld1_u8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_u8() {
|
||||
fn test_vld1q_u8() {
|
||||
let a: [u8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let e = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
let r: u8x16 = transmute(vld1q_u8(a[1..].as_ptr()));
|
||||
let r = unsafe { u8x16::from(vld1q_u8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_u16() {
|
||||
fn test_vld1_u16() {
|
||||
let a: [u16; 5] = [0, 1, 2, 3, 4];
|
||||
let e = u16x4::new(1, 2, 3, 4);
|
||||
let r: u16x4 = transmute(vld1_u16(a[1..].as_ptr()));
|
||||
let r = unsafe { u16x4::from(vld1_u16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_u16() {
|
||||
fn test_vld1q_u16() {
|
||||
let a: [u16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: u16x8 = transmute(vld1q_u16(a[1..].as_ptr()));
|
||||
let r = unsafe { u16x8::from(vld1q_u16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_u32() {
|
||||
fn test_vld1_u32() {
|
||||
let a: [u32; 3] = [0, 1, 2];
|
||||
let e = u32x2::new(1, 2);
|
||||
let r: u32x2 = transmute(vld1_u32(a[1..].as_ptr()));
|
||||
let r = unsafe { u32x2::from(vld1_u32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_u32() {
|
||||
fn test_vld1q_u32() {
|
||||
let a: [u32; 5] = [0, 1, 2, 3, 4];
|
||||
let e = u32x4::new(1, 2, 3, 4);
|
||||
let r: u32x4 = transmute(vld1q_u32(a[1..].as_ptr()));
|
||||
let r = unsafe { u32x4::from(vld1q_u32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_u64() {
|
||||
fn test_vld1_u64() {
|
||||
let a: [u64; 2] = [0, 1];
|
||||
let e = u64x1::new(1);
|
||||
let r: u64x1 = transmute(vld1_u64(a[1..].as_ptr()));
|
||||
let r = unsafe { u64x1::from(vld1_u64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_u64() {
|
||||
fn test_vld1q_u64() {
|
||||
let a: [u64; 3] = [0, 1, 2];
|
||||
let e = u64x2::new(1, 2);
|
||||
let r: u64x2 = transmute(vld1q_u64(a[1..].as_ptr()));
|
||||
let r = unsafe { u64x2::from(vld1q_u64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_p8() {
|
||||
fn test_vld1_p8() {
|
||||
let a: [p8; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: u8x8 = transmute(vld1_p8(a[1..].as_ptr()));
|
||||
let r = unsafe { u8x8::from(vld1_p8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_p8() {
|
||||
fn test_vld1q_p8() {
|
||||
let a: [p8; 17] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let e = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
let r: u8x16 = transmute(vld1q_p8(a[1..].as_ptr()));
|
||||
let r = unsafe { u8x16::from(vld1q_p8(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_p16() {
|
||||
fn test_vld1_p16() {
|
||||
let a: [p16; 5] = [0, 1, 2, 3, 4];
|
||||
let e = u16x4::new(1, 2, 3, 4);
|
||||
let r: u16x4 = transmute(vld1_p16(a[1..].as_ptr()));
|
||||
let r = unsafe { u16x4::from(vld1_p16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_p16() {
|
||||
fn test_vld1q_p16() {
|
||||
let a: [p16; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||
let e = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let r: u16x8 = transmute(vld1q_p16(a[1..].as_ptr()));
|
||||
let r = unsafe { u16x8::from(vld1q_p16(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon,aes")]
|
||||
unsafe fn test_vld1_p64() {
|
||||
fn test_vld1_p64() {
|
||||
let a: [p64; 2] = [0, 1];
|
||||
let e = u64x1::new(1);
|
||||
let r: u64x1 = transmute(vld1_p64(a[1..].as_ptr()));
|
||||
let r = unsafe { u64x1::from(vld1_p64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon,aes")]
|
||||
unsafe fn test_vld1q_p64() {
|
||||
fn test_vld1q_p64() {
|
||||
let a: [p64; 3] = [0, 1, 2];
|
||||
let e = u64x2::new(1, 2);
|
||||
let r: u64x2 = transmute(vld1q_p64(a[1..].as_ptr()));
|
||||
let r = unsafe { u64x2::from(vld1q_p64(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1_f32() {
|
||||
fn test_vld1_f32() {
|
||||
let a: [f32; 3] = [0., 1., 2.];
|
||||
let e = f32x2::new(1., 2.);
|
||||
let r: f32x2 = transmute(vld1_f32(a[1..].as_ptr()));
|
||||
let r = unsafe { f32x2::from(vld1_f32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vld1q_f32() {
|
||||
fn test_vld1q_f32() {
|
||||
let a: [f32; 5] = [0., 1., 2., 3., 4.];
|
||||
let e = f32x4::new(1., 2., 3., 4.);
|
||||
let r: f32x4 = transmute(vld1q_f32(a[1..].as_ptr()));
|
||||
let r = unsafe { f32x4::from(vld1q_f32(a[1..].as_ptr())) };
|
||||
assert_eq!(r, e)
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -14,11 +14,13 @@ use crate::core_arch::simd::*;
|
|||
use stdarch_test::simd_test;
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_s8() {
|
||||
fn test_vst1_s8() {
|
||||
let mut vals = [0_i8; 9];
|
||||
let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1_s8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_s8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -32,11 +34,13 @@ unsafe fn test_vst1_s8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_s8() {
|
||||
fn test_vst1q_s8() {
|
||||
let mut vals = [0_i8; 17];
|
||||
let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
|
||||
vst1q_s8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_s8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -58,11 +62,13 @@ unsafe fn test_vst1q_s8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_s16() {
|
||||
fn test_vst1_s16() {
|
||||
let mut vals = [0_i16; 5];
|
||||
let a = i16x4::new(1, 2, 3, 4);
|
||||
|
||||
vst1_s16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_s16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -72,11 +78,13 @@ unsafe fn test_vst1_s16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_s16() {
|
||||
fn test_vst1q_s16() {
|
||||
let mut vals = [0_i16; 9];
|
||||
let a = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1q_s16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_s16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -90,11 +98,13 @@ unsafe fn test_vst1q_s16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_s32() {
|
||||
fn test_vst1_s32() {
|
||||
let mut vals = [0_i32; 3];
|
||||
let a = i32x2::new(1, 2);
|
||||
|
||||
vst1_s32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_s32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -102,11 +112,13 @@ unsafe fn test_vst1_s32() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_s32() {
|
||||
fn test_vst1q_s32() {
|
||||
let mut vals = [0_i32; 5];
|
||||
let a = i32x4::new(1, 2, 3, 4);
|
||||
|
||||
vst1q_s32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_s32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -116,22 +128,26 @@ unsafe fn test_vst1q_s32() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_s64() {
|
||||
fn test_vst1_s64() {
|
||||
let mut vals = [0_i64; 2];
|
||||
let a = i64x1::new(1);
|
||||
|
||||
vst1_s64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_s64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_s64() {
|
||||
fn test_vst1q_s64() {
|
||||
let mut vals = [0_i64; 3];
|
||||
let a = i64x2::new(1, 2);
|
||||
|
||||
vst1q_s64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_s64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -139,11 +155,13 @@ unsafe fn test_vst1q_s64() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_u8() {
|
||||
fn test_vst1_u8() {
|
||||
let mut vals = [0_u8; 9];
|
||||
let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1_u8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_u8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -157,11 +175,13 @@ unsafe fn test_vst1_u8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_u8() {
|
||||
fn test_vst1q_u8() {
|
||||
let mut vals = [0_u8; 17];
|
||||
let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
|
||||
vst1q_u8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_u8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -183,11 +203,13 @@ unsafe fn test_vst1q_u8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_u16() {
|
||||
fn test_vst1_u16() {
|
||||
let mut vals = [0_u16; 5];
|
||||
let a = u16x4::new(1, 2, 3, 4);
|
||||
|
||||
vst1_u16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_u16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -197,11 +219,13 @@ unsafe fn test_vst1_u16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_u16() {
|
||||
fn test_vst1q_u16() {
|
||||
let mut vals = [0_u16; 9];
|
||||
let a = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1q_u16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_u16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -215,11 +239,13 @@ unsafe fn test_vst1q_u16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_u32() {
|
||||
fn test_vst1_u32() {
|
||||
let mut vals = [0_u32; 3];
|
||||
let a = u32x2::new(1, 2);
|
||||
|
||||
vst1_u32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_u32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -227,11 +253,13 @@ unsafe fn test_vst1_u32() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_u32() {
|
||||
fn test_vst1q_u32() {
|
||||
let mut vals = [0_u32; 5];
|
||||
let a = u32x4::new(1, 2, 3, 4);
|
||||
|
||||
vst1q_u32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_u32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -241,22 +269,26 @@ unsafe fn test_vst1q_u32() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_u64() {
|
||||
fn test_vst1_u64() {
|
||||
let mut vals = [0_u64; 2];
|
||||
let a = u64x1::new(1);
|
||||
|
||||
vst1_u64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_u64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_u64() {
|
||||
fn test_vst1q_u64() {
|
||||
let mut vals = [0_u64; 3];
|
||||
let a = u64x2::new(1, 2);
|
||||
|
||||
vst1q_u64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_u64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -264,11 +296,13 @@ unsafe fn test_vst1q_u64() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_p8() {
|
||||
fn test_vst1_p8() {
|
||||
let mut vals = [0_u8; 9];
|
||||
let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1_p8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_p8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -282,11 +316,13 @@ unsafe fn test_vst1_p8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_p8() {
|
||||
fn test_vst1q_p8() {
|
||||
let mut vals = [0_u8; 17];
|
||||
let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
|
||||
|
||||
vst1q_p8(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_p8(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -308,11 +344,13 @@ unsafe fn test_vst1q_p8() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_p16() {
|
||||
fn test_vst1_p16() {
|
||||
let mut vals = [0_u16; 5];
|
||||
let a = u16x4::new(1, 2, 3, 4);
|
||||
|
||||
vst1_p16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_p16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -322,11 +360,13 @@ unsafe fn test_vst1_p16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_p16() {
|
||||
fn test_vst1q_p16() {
|
||||
let mut vals = [0_u16; 9];
|
||||
let a = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
vst1q_p16(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_p16(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -340,22 +380,26 @@ unsafe fn test_vst1q_p16() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon,aes")]
|
||||
unsafe fn test_vst1_p64() {
|
||||
fn test_vst1_p64() {
|
||||
let mut vals = [0_u64; 2];
|
||||
let a = u64x1::new(1);
|
||||
|
||||
vst1_p64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_p64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "neon,aes")]
|
||||
unsafe fn test_vst1q_p64() {
|
||||
fn test_vst1q_p64() {
|
||||
let mut vals = [0_u64; 3];
|
||||
let a = u64x2::new(1, 2);
|
||||
|
||||
vst1q_p64(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_p64(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0);
|
||||
assert_eq!(vals[1], 1);
|
||||
|
|
@ -363,11 +407,13 @@ unsafe fn test_vst1q_p64() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1_f32() {
|
||||
fn test_vst1_f32() {
|
||||
let mut vals = [0_f32; 3];
|
||||
let a = f32x2::new(1., 2.);
|
||||
|
||||
vst1_f32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1_f32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0.);
|
||||
assert_eq!(vals[1], 1.);
|
||||
|
|
@ -375,11 +421,13 @@ unsafe fn test_vst1_f32() {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn test_vst1q_f32() {
|
||||
fn test_vst1q_f32() {
|
||||
let mut vals = [0_f32; 5];
|
||||
let a = f32x4::new(1., 2., 3., 4.);
|
||||
|
||||
vst1q_f32(vals[1..].as_mut_ptr(), transmute(a));
|
||||
unsafe {
|
||||
vst1q_f32(vals[1..].as_mut_ptr(), a.into());
|
||||
}
|
||||
|
||||
assert_eq!(vals[0], 0.);
|
||||
assert_eq!(vals[1], 1.);
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ macro_rules! test_vtbl {
|
|||
) => {
|
||||
#[cfg(target_endian = "little")]
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn $test_name() {
|
||||
fn $test_name() {
|
||||
// create table as array, and transmute it to
|
||||
// arm's table type
|
||||
let table: $table_t = mem::transmute([$($table_v),*]);
|
||||
let table: $table_t = unsafe { mem::transmute([$($table_v),*]) };
|
||||
|
||||
// For each control vector, perform a table lookup and
|
||||
// verify the result:
|
||||
$(
|
||||
{
|
||||
let ctrl: $ctrl_t = mem::transmute([$($ctrl_v),*]);
|
||||
let result = $fn_id(table, mem::transmute(ctrl));
|
||||
let result: $ctrl_t = mem::transmute(result);
|
||||
let expected: $ctrl_t = mem::transmute([$($exp_v),*]);
|
||||
let ctrl: $ctrl_t = unsafe { mem::transmute([$($ctrl_v),*]) };
|
||||
let result = $fn_id(table, unsafe { mem::transmute(ctrl) });
|
||||
let result: $ctrl_t = unsafe { mem::transmute(result) };
|
||||
let expected: $ctrl_t = unsafe { mem::transmute([$($exp_v),*]) };
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
)*
|
||||
|
|
@ -171,20 +171,19 @@ macro_rules! test_vtbx {
|
|||
) => {
|
||||
#[cfg(target_endian = "little")]
|
||||
#[simd_test(enable = "neon")]
|
||||
unsafe fn $test_name() {
|
||||
fn $test_name() {
|
||||
// create table as array, and transmute it to
|
||||
// arm's table type
|
||||
let table: $table_t = mem::transmute([$($table_v),*]);
|
||||
let ext: $ext_t = mem::transmute([$($ext_v),*]);
|
||||
|
||||
let table: $table_t = unsafe { mem::transmute([$($table_v),*]) };
|
||||
let ext: $ext_t = unsafe { mem::transmute([$($ext_v),*]) };
|
||||
// For each control vector, perform a table lookup and
|
||||
// verify the result:
|
||||
$(
|
||||
{
|
||||
let ctrl: $ctrl_t = mem::transmute([$($ctrl_v),*]);
|
||||
let result = $fn_id(ext, table, mem::transmute(ctrl));
|
||||
let result: $ctrl_t = mem::transmute(result);
|
||||
let expected: $ctrl_t = mem::transmute([$($exp_v),*]);
|
||||
let ctrl: $ctrl_t = unsafe { mem::transmute([$($ctrl_v),*]) };
|
||||
let result = $fn_id(ext, table, unsafe { mem::transmute(ctrl) });
|
||||
let result: $ctrl_t = unsafe { mem::transmute(result) };
|
||||
let expected: $ctrl_t = unsafe { mem::transmute([$($exp_v),*]) };
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
)*
|
||||
|
|
|
|||
|
|
@ -111,13 +111,13 @@ macro_rules! V_f32 {
|
|||
|
||||
macro_rules! to64 {
|
||||
($t : ident) => {
|
||||
|v: $t| -> u64 { transmute(v) }
|
||||
|v: $t| -> u64 { unsafe { transmute(v) } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! to128 {
|
||||
($t : ident) => {
|
||||
|v: $t| -> u128 { transmute(v) }
|
||||
|v: $t| -> u128 { unsafe { transmute(v) } }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -158,9 +158,7 @@ pub(crate) fn test<T, U, V, W, X>(
|
|||
macro_rules! gen_test_fn {
|
||||
($n: ident, $t: ident, $u: ident, $v: ident, $w: ident, $x: ident, $vals: expr, $fill1: expr, $fill2: expr, $cast: expr) => {
|
||||
pub(crate) fn $n(test_fun: fn($v, $v) -> $w, verify_fun: fn($t, $t) -> $u) {
|
||||
unsafe {
|
||||
test::<$t, $u, $v, $w, $x>($vals, $fill1, $fill2, $cast, test_fun, verify_fun)
|
||||
};
|
||||
test::<$t, $u, $v, $w, $x>($vals, $fill1, $fill2, $cast, test_fun, verify_fun);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,12 +32,14 @@
|
|||
x86_amx_intrinsics,
|
||||
f16,
|
||||
aarch64_unstable_target_feature,
|
||||
target_feature_inline_always,
|
||||
bigint_helper_methods,
|
||||
funnel_shifts,
|
||||
avx10_target_feature,
|
||||
const_trait_impl,
|
||||
const_cmp,
|
||||
const_eval_select
|
||||
const_eval_select,
|
||||
maybe_uninit_as_bytes
|
||||
)]
|
||||
#![cfg_attr(test, feature(test, abi_vectorcall, stdarch_internal))]
|
||||
#![deny(clippy::missing_inline_in_public_items)]
|
||||
|
|
@ -87,4 +89,4 @@ pub mod arch {
|
|||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use core::{array, convert, ffi, fmt, hint, intrinsics, marker, mem, ops, ptr, sync};
|
||||
use core::{array, cmp, convert, ffi, fmt, hint, intrinsics, marker, mem, ops, ptr, sync};
|
||||
|
|
|
|||
|
|
@ -90,17 +90,10 @@ macro_rules! types {
|
|||
pub struct $name($v [$elem_type; $len]);
|
||||
|
||||
impl $name {
|
||||
/// Using `my_simd([x; N])` seemingly fails tests,
|
||||
/// so use this internal helper for it instead.
|
||||
/// Put the same value in every lane.
|
||||
#[inline(always)]
|
||||
$v fn splat(value: $elem_type) -> $name {
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(simd)]
|
||||
struct JustOne([$elem_type; 1]);
|
||||
let one = JustOne([value]);
|
||||
// SAFETY: 0 is always in-bounds because we're shuffling
|
||||
// a simd type with exactly one element.
|
||||
unsafe { simd_shuffle!(one, one, [0; $len]) }
|
||||
unsafe { $crate::intrinsics::simd::simd_splat(value) }
|
||||
}
|
||||
|
||||
/// Returns an array reference containing the entire SIMD vector.
|
||||
|
|
@ -135,6 +128,22 @@ macro_rules! types {
|
|||
crate::core_arch::simd::debug_simd_finish(f, stringify!($name), self.as_array())
|
||||
}
|
||||
}
|
||||
|
||||
$(#[$stability])+
|
||||
impl crate::convert::From<crate::core_arch::simd::Simd<$elem_type, $len>> for $name {
|
||||
#[inline(always)]
|
||||
fn from(simd: crate::core_arch::simd::Simd<$elem_type, $len>) -> Self {
|
||||
unsafe { crate::mem::transmute(simd) }
|
||||
}
|
||||
}
|
||||
|
||||
$(#[$stability])+
|
||||
impl crate::convert::From<$name> for crate::core_arch::simd::Simd<$elem_type, $len> {
|
||||
#[inline(always)]
|
||||
fn from(simd: $name) -> Self {
|
||||
unsafe { crate::mem::transmute(simd) }
|
||||
}
|
||||
}
|
||||
)*);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,29 +23,29 @@ unsafe extern "C" {
|
|||
#[link_name = "llvm.nvvm.barrier0"]
|
||||
fn syncthreads() -> ();
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ntid.x"]
|
||||
fn block_dim_x() -> i32;
|
||||
fn block_dim_x() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ntid.y"]
|
||||
fn block_dim_y() -> i32;
|
||||
fn block_dim_y() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ntid.z"]
|
||||
fn block_dim_z() -> i32;
|
||||
fn block_dim_z() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.x"]
|
||||
fn block_idx_x() -> i32;
|
||||
fn block_idx_x() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.y"]
|
||||
fn block_idx_y() -> i32;
|
||||
fn block_idx_y() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.z"]
|
||||
fn block_idx_z() -> i32;
|
||||
fn block_idx_z() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.x"]
|
||||
fn grid_dim_x() -> i32;
|
||||
fn grid_dim_x() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.y"]
|
||||
fn grid_dim_y() -> i32;
|
||||
fn grid_dim_y() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.z"]
|
||||
fn grid_dim_z() -> i32;
|
||||
fn grid_dim_z() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.tid.x"]
|
||||
fn thread_idx_x() -> i32;
|
||||
fn thread_idx_x() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.tid.y"]
|
||||
fn thread_idx_y() -> i32;
|
||||
fn thread_idx_y() -> u32;
|
||||
#[link_name = "llvm.nvvm.read.ptx.sreg.tid.z"]
|
||||
fn thread_idx_z() -> i32;
|
||||
fn thread_idx_z() -> u32;
|
||||
}
|
||||
|
||||
/// Synchronizes all threads in the block.
|
||||
|
|
@ -58,84 +58,84 @@ pub unsafe fn _syncthreads() -> () {
|
|||
/// x-th thread-block dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_dim_x() -> i32 {
|
||||
pub unsafe fn _block_dim_x() -> u32 {
|
||||
block_dim_x()
|
||||
}
|
||||
|
||||
/// y-th thread-block dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_dim_y() -> i32 {
|
||||
pub unsafe fn _block_dim_y() -> u32 {
|
||||
block_dim_y()
|
||||
}
|
||||
|
||||
/// z-th thread-block dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_dim_z() -> i32 {
|
||||
pub unsafe fn _block_dim_z() -> u32 {
|
||||
block_dim_z()
|
||||
}
|
||||
|
||||
/// x-th thread-block index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_idx_x() -> i32 {
|
||||
pub unsafe fn _block_idx_x() -> u32 {
|
||||
block_idx_x()
|
||||
}
|
||||
|
||||
/// y-th thread-block index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_idx_y() -> i32 {
|
||||
pub unsafe fn _block_idx_y() -> u32 {
|
||||
block_idx_y()
|
||||
}
|
||||
|
||||
/// z-th thread-block index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _block_idx_z() -> i32 {
|
||||
pub unsafe fn _block_idx_z() -> u32 {
|
||||
block_idx_z()
|
||||
}
|
||||
|
||||
/// x-th block-grid dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _grid_dim_x() -> i32 {
|
||||
pub unsafe fn _grid_dim_x() -> u32 {
|
||||
grid_dim_x()
|
||||
}
|
||||
|
||||
/// y-th block-grid dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _grid_dim_y() -> i32 {
|
||||
pub unsafe fn _grid_dim_y() -> u32 {
|
||||
grid_dim_y()
|
||||
}
|
||||
|
||||
/// z-th block-grid dimension.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _grid_dim_z() -> i32 {
|
||||
pub unsafe fn _grid_dim_z() -> u32 {
|
||||
grid_dim_z()
|
||||
}
|
||||
|
||||
/// x-th thread index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _thread_idx_x() -> i32 {
|
||||
pub unsafe fn _thread_idx_x() -> u32 {
|
||||
thread_idx_x()
|
||||
}
|
||||
|
||||
/// y-th thread index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _thread_idx_y() -> i32 {
|
||||
pub unsafe fn _thread_idx_y() -> u32 {
|
||||
thread_idx_y()
|
||||
}
|
||||
|
||||
/// z-th thread index.
|
||||
#[inline]
|
||||
#[unstable(feature = "stdarch_nvptx", issue = "111199")]
|
||||
pub unsafe fn _thread_idx_z() -> i32 {
|
||||
pub unsafe fn _thread_idx_z() -> u32 {
|
||||
thread_idx_z()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,17 +364,46 @@ unsafe extern "C" {
|
|||
fn vrfin(a: vector_float) -> vector_float;
|
||||
}
|
||||
|
||||
impl_from! { i8x16, u8x16, i16x8, u16x8, i32x4, u32x4, f32x4 }
|
||||
|
||||
impl_neg! { i8x16 : 0 }
|
||||
impl_neg! { i16x8 : 0 }
|
||||
impl_neg! { i32x4 : 0 }
|
||||
impl_neg! { f32x4 : 0f32 }
|
||||
|
||||
#[macro_use]
|
||||
mod sealed {
|
||||
use super::*;
|
||||
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
pub trait VectorNeg {
|
||||
unsafe fn vec_neg(self) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! impl_neg {
|
||||
($($v:ty)*) => {
|
||||
$(
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
impl VectorNeg for $v {
|
||||
#[inline]
|
||||
#[target_feature(enable = "altivec")]
|
||||
unsafe fn vec_neg(self) -> Self {
|
||||
simd_neg(self)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_neg! {
|
||||
vector_signed_char
|
||||
vector_unsigned_char
|
||||
vector_bool_char
|
||||
|
||||
vector_signed_short
|
||||
vector_unsigned_short
|
||||
vector_bool_short
|
||||
|
||||
vector_signed_int
|
||||
vector_unsigned_int
|
||||
vector_bool_int
|
||||
|
||||
vector_float
|
||||
}
|
||||
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
pub trait VectorInsert {
|
||||
type Scalar;
|
||||
|
|
@ -1380,7 +1409,7 @@ mod sealed {
|
|||
#[inline]
|
||||
#[target_feature(enable = "altivec")]
|
||||
unsafe fn $name(v: s_t_l!($ty)) -> s_t_l!($ty) {
|
||||
v.vec_max(-v)
|
||||
v.vec_max(simd_neg(v))
|
||||
}
|
||||
|
||||
impl_vec_trait! { [VectorAbs vec_abs] $name (s_t_l!($ty)) }
|
||||
|
|
@ -1428,7 +1457,7 @@ mod sealed {
|
|||
#[cfg_attr(test, assert_instr(vspltb, IMM4 = 15))]
|
||||
unsafe fn vspltb<const IMM4: u32>(a: vector_signed_char) -> vector_signed_char {
|
||||
static_assert_uimm_bits!(IMM4, 4);
|
||||
simd_shuffle(a, a, const { u32x16::from_array([IMM4; 16]) })
|
||||
simd_shuffle(a, a, const { u32x16::splat(IMM4) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1436,7 +1465,7 @@ mod sealed {
|
|||
#[cfg_attr(test, assert_instr(vsplth, IMM3 = 7))]
|
||||
unsafe fn vsplth<const IMM3: u32>(a: vector_signed_short) -> vector_signed_short {
|
||||
static_assert_uimm_bits!(IMM3, 3);
|
||||
simd_shuffle(a, a, const { u32x8::from_array([IMM3; 8]) })
|
||||
simd_shuffle(a, a, const { u32x8::splat(IMM3) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1445,7 +1474,7 @@ mod sealed {
|
|||
#[cfg_attr(all(test, target_feature = "vsx"), assert_instr(xxspltw, IMM2 = 3))]
|
||||
unsafe fn vspltw<const IMM2: u32>(a: vector_signed_int) -> vector_signed_int {
|
||||
static_assert_uimm_bits!(IMM2, 2);
|
||||
simd_shuffle(a, a, const { u32x4::from_array([IMM2; 4]) })
|
||||
simd_shuffle(a, a, const { u32x4::splat(IMM2) })
|
||||
}
|
||||
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
|
|
@ -4032,6 +4061,14 @@ pub unsafe fn vec_mfvscr() -> vector_unsigned_short {
|
|||
mfvscr()
|
||||
}
|
||||
|
||||
/// Vector Negate
|
||||
#[inline]
|
||||
#[target_feature(enable = "altivec")]
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
pub unsafe fn vec_neg<T: sealed::VectorNeg>(a: T) -> T {
|
||||
a.vec_neg()
|
||||
}
|
||||
|
||||
/// Vector add.
|
||||
#[inline]
|
||||
#[target_feature(enable = "altivec")]
|
||||
|
|
@ -4703,7 +4740,7 @@ mod tests {
|
|||
for off in 0..16 {
|
||||
let val: u8x16 = transmute(vec_xl(0, (pat.as_ptr() as *const u8).offset(off)));
|
||||
for i in 0..16 {
|
||||
let v = val.extract(i);
|
||||
let v = val.extract_dyn(i);
|
||||
assert_eq!(off as usize + i, v as usize);
|
||||
}
|
||||
}
|
||||
|
|
@ -4758,7 +4795,7 @@ mod tests {
|
|||
)];
|
||||
for off in 0..16 {
|
||||
let v: u8x16 = transmute(vec_lde(off, pat.as_ptr() as *const u8));
|
||||
assert_eq!(off as u8, v.extract(off as _));
|
||||
assert_eq!(off as u8, v.extract_dyn(off as _));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4767,7 +4804,7 @@ mod tests {
|
|||
let pat = [u16x8::new(0, 1, 2, 3, 4, 5, 6, 7)];
|
||||
for off in 0..8 {
|
||||
let v: u16x8 = transmute(vec_lde(off * 2, pat.as_ptr() as *const u16));
|
||||
assert_eq!(off as u16, v.extract(off as _));
|
||||
assert_eq!(off as u16, v.extract_dyn(off as _));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4776,7 +4813,7 @@ mod tests {
|
|||
let pat = [u32x4::new(0, 1, 2, 3)];
|
||||
for off in 0..4 {
|
||||
let v: u32x4 = transmute(vec_lde(off * 4, pat.as_ptr() as *const u32));
|
||||
assert_eq!(off as u32, v.extract(off as _));
|
||||
assert_eq!(off as u32, v.extract_dyn(off as _));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,40 +274,6 @@ macro_rules! t_b {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from {
|
||||
($s: ident) => {
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
impl From<$s> for s_t_l!($s) {
|
||||
#[inline]
|
||||
fn from (v: $s) -> Self {
|
||||
unsafe {
|
||||
transmute(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
($($s: ident),*) => {
|
||||
$(
|
||||
impl_from! { $s }
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_neg {
|
||||
($s: ident : $zero: expr) => {
|
||||
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
|
||||
impl crate::ops::Neg for s_t_l!($s) {
|
||||
type Output = s_t_l!($s);
|
||||
#[inline]
|
||||
fn neg(self) -> Self::Output {
|
||||
unsafe { simd_neg(self) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use impl_from;
|
||||
pub(crate) use impl_neg;
|
||||
pub(crate) use impl_vec_trait;
|
||||
pub(crate) use s_t_l;
|
||||
pub(crate) use t_b;
|
||||
|
|
|
|||
|
|
@ -431,40 +431,6 @@ macro_rules! t_b {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from {
|
||||
($s: ident) => {
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
impl From<$s> for s_t_l!($s) {
|
||||
#[inline]
|
||||
fn from (v: $s) -> Self {
|
||||
unsafe {
|
||||
transmute(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
($($s: ident),*) => {
|
||||
$(
|
||||
impl_from! { $s }
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_neg {
|
||||
($s: ident : $zero: expr) => {
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
impl crate::ops::Neg for s_t_l!($s) {
|
||||
type Output = s_t_l!($s);
|
||||
#[inline]
|
||||
fn neg(self) -> Self::Output {
|
||||
unsafe { simd_neg(self) }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use impl_from;
|
||||
pub(crate) use impl_neg;
|
||||
pub(crate) use impl_vec_trait;
|
||||
pub(crate) use l_t_t;
|
||||
pub(crate) use s_t_l;
|
||||
|
|
|
|||
|
|
@ -281,17 +281,14 @@ unsafe extern "unadjusted" {
|
|||
#[link_name = "llvm.s390.vfenezbs"] fn vfenezbs(a: i8x16, b: i8x16) -> PackedTuple<i8x16, i32>;
|
||||
#[link_name = "llvm.s390.vfenezhs"] fn vfenezhs(a: i16x8, b: i16x8) -> PackedTuple<i16x8, i32>;
|
||||
#[link_name = "llvm.s390.vfenezfs"] fn vfenezfs(a: i32x4, b: i32x4) -> PackedTuple<i32x4, i32>;
|
||||
|
||||
#[link_name = "llvm.s390.vclfnhs"] fn vclfnhs(a: vector_signed_short, immarg: i32) -> vector_float;
|
||||
#[link_name = "llvm.s390.vclfnls"] fn vclfnls(a: vector_signed_short, immarg: i32) -> vector_float;
|
||||
#[link_name = "llvm.s390.vcfn"] fn vcfn(a: vector_signed_short, immarg: i32) -> vector_signed_short;
|
||||
#[link_name = "llvm.s390.vcnf"] fn vcnf(a: vector_signed_short, immarg: i32) -> vector_signed_short;
|
||||
#[link_name = "llvm.s390.vcrnfs"] fn vcrnfs(a: vector_float, b: vector_float, immarg: i32) -> vector_signed_short;
|
||||
}
|
||||
|
||||
impl_from! { i8x16, u8x16, i16x8, u16x8, i32x4, u32x4, i64x2, u64x2, f32x4, f64x2 }
|
||||
|
||||
impl_neg! { i8x16 : 0 }
|
||||
impl_neg! { i16x8 : 0 }
|
||||
impl_neg! { i32x4 : 0 }
|
||||
impl_neg! { i64x2 : 0 }
|
||||
impl_neg! { f32x4 : 0f32 }
|
||||
impl_neg! { f64x2 : 0f64 }
|
||||
|
||||
#[repr(simd)]
|
||||
struct ShuffleMask<const N: usize>([u32; N]);
|
||||
|
||||
|
|
@ -439,6 +436,43 @@ enum FindImm {
|
|||
mod sealed {
|
||||
use super::*;
|
||||
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub trait VectorNeg {
|
||||
unsafe fn vec_neg(self) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! impl_neg {
|
||||
($($v:ty)*) => {
|
||||
$(
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
impl VectorNeg for $v {
|
||||
#[inline]
|
||||
#[target_feature(enable = "vector")]
|
||||
unsafe fn vec_neg(self) -> Self {
|
||||
simd_neg(self)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_neg! {
|
||||
vector_signed_char
|
||||
vector_unsigned_char
|
||||
|
||||
vector_signed_short
|
||||
vector_unsigned_short
|
||||
|
||||
vector_signed_int
|
||||
vector_unsigned_int
|
||||
|
||||
vector_signed_long_long
|
||||
vector_unsigned_long_long
|
||||
|
||||
vector_float
|
||||
vector_double
|
||||
}
|
||||
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub trait VectorAdd<Other> {
|
||||
type Result;
|
||||
|
|
@ -761,7 +795,7 @@ mod sealed {
|
|||
#[inline]
|
||||
#[target_feature(enable = "vector")]
|
||||
unsafe fn $name(v: s_t_l!($ty)) -> s_t_l!($ty) {
|
||||
v.vec_max(-v)
|
||||
v.vec_max(simd_neg(v))
|
||||
}
|
||||
|
||||
impl_vec_trait! { [VectorAbs vec_abs] $name (s_t_l!($ty)) }
|
||||
|
|
@ -4055,6 +4089,14 @@ unsafe fn __lcbb<const BLOCK_BOUNDARY: u16>(ptr: *const u8) -> u32 {
|
|||
lcbb(ptr, const { validate_block_boundary(BLOCK_BOUNDARY) })
|
||||
}
|
||||
|
||||
/// Vector Negate
|
||||
#[inline]
|
||||
#[target_feature(enable = "vector")]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub unsafe fn vec_neg<T: sealed::VectorNeg>(a: T) -> T {
|
||||
a.vec_neg()
|
||||
}
|
||||
|
||||
/// Vector Add
|
||||
#[inline]
|
||||
#[target_feature(enable = "vector")]
|
||||
|
|
@ -5875,6 +5917,74 @@ pub unsafe fn vec_promote<T: sealed::VectorPromote>(a: T::ElementType, b: i32) -
|
|||
T::vec_promote(a, b)
|
||||
}
|
||||
|
||||
/// Converts the left-most half of `a` to a vector of single-precision numbers.
|
||||
/// The format of the source vector elements is specified by `B`.
|
||||
#[inline]
|
||||
#[target_feature(enable = "nnp-assist")]
|
||||
#[cfg_attr(test, assert_instr(vclfnh, B = 0))]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub unsafe fn vec_extend_to_fp32_hi<const B: i32>(a: vector_signed_short) -> vector_float {
|
||||
// On processors implementing the IBM z16 architecture, only the value 0 is supported.
|
||||
static_assert_uimm_bits!(B, 4);
|
||||
|
||||
vclfnhs(a, B)
|
||||
}
|
||||
|
||||
/// Converts the right-most half of `a` to a vector of single-precision numbers.
|
||||
/// The format of the source vector elements is specified by `B`.
|
||||
#[inline]
|
||||
#[target_feature(enable = "nnp-assist")]
|
||||
#[cfg_attr(test, assert_instr(vclfnl, B = 0))]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub unsafe fn vec_extend_to_fp32_lo<const B: i32>(a: vector_signed_short) -> vector_float {
|
||||
// On processors implementing the IBM z16 architecture, only the value 0 is supported.
|
||||
static_assert_uimm_bits!(B, 4);
|
||||
|
||||
vclfnls(a, B)
|
||||
}
|
||||
|
||||
/// Converts the elements of vector `a` to the 16-bit IEEE floating point format.
|
||||
/// The format of the source vector elements is specified by `B`.
|
||||
#[inline]
|
||||
#[target_feature(enable = "nnp-assist")]
|
||||
#[cfg_attr(test, assert_instr(vcfn, B = 0))]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub unsafe fn vec_convert_to_fp16<const B: i32>(a: vector_signed_short) -> vector_signed_short {
|
||||
// On processors implementing the IBM z16 architecture, only the value 0 is supported.
|
||||
static_assert_uimm_bits!(B, 4);
|
||||
|
||||
vcfn(a, B)
|
||||
}
|
||||
|
||||
/// Converts the elements of vector `a` to an internal floating point format.
|
||||
/// The format of the target vector elements is specified by `B`.
|
||||
#[inline]
|
||||
#[target_feature(enable = "nnp-assist")]
|
||||
#[cfg_attr(test, assert_instr(vcnf, B = 0))]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
pub unsafe fn vec_convert_from_fp16<const B: i32>(a: vector_signed_short) -> vector_signed_short {
|
||||
// On processors implementing the IBM z16 architecture, only the value 0 is supported.
|
||||
static_assert_uimm_bits!(B, 4);
|
||||
|
||||
vcnf(a, B)
|
||||
}
|
||||
|
||||
/// Converts the elements of single-precision vectors `a` and `b` to an internal floating point
|
||||
/// format with 16-bit sized elements. The format of the target vector elements is specified by `C`.
|
||||
#[inline]
|
||||
#[target_feature(enable = "nnp-assist")]
|
||||
#[unstable(feature = "stdarch_s390x", issue = "135681")]
|
||||
#[cfg_attr(test, assert_instr(vcrnf, C = 0))]
|
||||
pub unsafe fn vec_round_from_fp32<const C: i32>(
|
||||
a: vector_float,
|
||||
b: vector_float,
|
||||
) -> vector_signed_short {
|
||||
// On processors implementing the IBM z16 architecture, only the value 0 is supported.
|
||||
static_assert_uimm_bits!(C, 4);
|
||||
|
||||
vcrnfs(a, b, C)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -16,129 +16,216 @@ pub(crate) const unsafe fn simd_imin<T: Copy>(a: T, b: T) -> T {
|
|||
crate::intrinsics::simd::simd_select(mask, a, b)
|
||||
}
|
||||
|
||||
/// SAFETY: All bits patterns must be valid
|
||||
pub(crate) unsafe trait SimdElement:
|
||||
Copy + const PartialEq + crate::fmt::Debug
|
||||
{
|
||||
}
|
||||
|
||||
unsafe impl SimdElement for u8 {}
|
||||
unsafe impl SimdElement for u16 {}
|
||||
unsafe impl SimdElement for u32 {}
|
||||
unsafe impl SimdElement for u64 {}
|
||||
|
||||
unsafe impl SimdElement for i8 {}
|
||||
unsafe impl SimdElement for i16 {}
|
||||
unsafe impl SimdElement for i32 {}
|
||||
unsafe impl SimdElement for i64 {}
|
||||
|
||||
unsafe impl SimdElement for f16 {}
|
||||
unsafe impl SimdElement for f32 {}
|
||||
unsafe impl SimdElement for f64 {}
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy)]
|
||||
pub(crate) struct Simd<T: SimdElement, const N: usize>([T; N]);
|
||||
|
||||
impl<T: SimdElement, const N: usize> Simd<T, N> {
|
||||
/// A value of this type where all elements are zeroed out.
|
||||
// SAFETY: `T` implements `SimdElement`, so it is zeroable.
|
||||
pub(crate) const ZERO: Self = unsafe { crate::mem::zeroed() };
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) const fn from_array(elements: [T; N]) -> Self {
|
||||
Self(elements)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn splat(value: T) -> Self {
|
||||
unsafe { crate::intrinsics::simd::simd_splat(value) }
|
||||
}
|
||||
|
||||
/// Extract the element at position `index`. Note that `index` is not a constant so this
|
||||
/// operation is not efficient on most platforms. Use for testing only.
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn extract_dyn(&self, index: usize) -> T {
|
||||
assert!(index < N);
|
||||
// SAFETY: self is a vector, T its element type.
|
||||
unsafe { crate::intrinsics::simd::simd_extract_dyn(*self, index as u32) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn as_array(&self) -> &[T; N] {
|
||||
let simd_ptr: *const Self = self;
|
||||
let array_ptr: *const [T; N] = simd_ptr.cast();
|
||||
// SAFETY: We can always read the prefix of a simd type as an array.
|
||||
// There might be more padding afterwards for some widths, but
|
||||
// that's not a problem for reading less than that.
|
||||
unsafe { &*array_ptr }
|
||||
}
|
||||
}
|
||||
|
||||
// `#[derive(Clone)]` causes ICE "Projecting into SIMD type core_arch::simd::Simd is banned by MCP#838"
|
||||
impl<T: SimdElement, const N: usize> Clone for Simd<T, N> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
impl<T: SimdElement, const N: usize> const crate::cmp::PartialEq for Simd<T, N> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_array() == other.as_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SimdElement, const N: usize> crate::fmt::Debug for Simd<T, N> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
|
||||
debug_simd_finish(f, "Simd", self.as_array())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Simd<f16, N> {
|
||||
#[inline]
|
||||
pub(crate) const fn to_bits(self) -> Simd<u16, N> {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u16, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn from_bits(bits: Simd<u16, N>) -> Self {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u16, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&bits) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Simd<f32, N> {
|
||||
#[inline]
|
||||
pub(crate) const fn to_bits(self) -> Simd<u32, N> {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u32, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn from_bits(bits: Simd<u32, N>) -> Self {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u32, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&bits) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Simd<f64, N> {
|
||||
#[inline]
|
||||
pub(crate) const fn to_bits(self) -> Simd<u64, N> {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u64, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn from_bits(bits: Simd<u64, N>) -> Self {
|
||||
assert!(size_of::<Self>() == size_of::<Simd<u64, N>>());
|
||||
unsafe { crate::mem::transmute_copy(&bits) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! simd_ty {
|
||||
($id:ident [$elem_type:ty ; $len:literal]: $($param_name:ident),*) => {
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct $id([$elem_type; $len]);
|
||||
pub(crate) type $id = Simd<$elem_type, $len>;
|
||||
|
||||
#[allow(clippy::use_self)]
|
||||
impl $id {
|
||||
/// A value of this type where all elements are zeroed out.
|
||||
pub(crate) const ZERO: Self = unsafe { crate::mem::zeroed() };
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) const fn new($($param_name: $elem_type),*) -> Self {
|
||||
$id([$($param_name),*])
|
||||
}
|
||||
#[inline(always)]
|
||||
pub(crate) const fn from_array(elements: [$elem_type; $len]) -> Self {
|
||||
$id(elements)
|
||||
}
|
||||
// FIXME: Workaround rust@60637
|
||||
#[inline(always)]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn splat(value: $elem_type) -> Self {
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(simd)]
|
||||
struct JustOne([$elem_type; 1]);
|
||||
let one = JustOne([value]);
|
||||
// SAFETY: 0 is always in-bounds because we're shuffling
|
||||
// a simd type with exactly one element.
|
||||
unsafe { simd_shuffle!(one, one, [0; $len]) }
|
||||
}
|
||||
|
||||
/// Extract the element at position `index`.
|
||||
/// `index` is not a constant so this is not efficient!
|
||||
/// Use for testing only.
|
||||
// FIXME: Workaround rust@60637
|
||||
#[inline(always)]
|
||||
pub(crate) const fn extract(&self, index: usize) -> $elem_type {
|
||||
self.as_array()[index]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn as_array(&self) -> &[$elem_type; $len] {
|
||||
let simd_ptr: *const Self = self;
|
||||
let array_ptr: *const [$elem_type; $len] = simd_ptr.cast();
|
||||
// SAFETY: We can always read the prefix of a simd type as an array.
|
||||
// There might be more padding afterwards for some widths, but
|
||||
// that's not a problem for reading less than that.
|
||||
unsafe { &*array_ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
const impl core::cmp::PartialEq for $id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_array() == other.as_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for $id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
debug_simd_finish(f, stringify!($id), self.as_array())
|
||||
Self([$($param_name),*])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy)]
|
||||
pub(crate) struct SimdM<T: SimdElement, const N: usize>([T; N]);
|
||||
|
||||
impl<T: SimdElement, const N: usize> SimdM<T, N> {
|
||||
#[inline(always)]
|
||||
const fn bool_to_internal(x: bool) -> T {
|
||||
// SAFETY: `T` implements `SimdElement`, so all bit patterns are valid.
|
||||
let zeros = const { unsafe { crate::mem::zeroed::<T>() } };
|
||||
let ones = const {
|
||||
// Ideally, this would be `transmute([0xFFu8; size_of::<T>()])`, but
|
||||
// `size_of::<T>()` is not allowed to use a generic parameter there.
|
||||
let mut r = crate::mem::MaybeUninit::<T>::uninit();
|
||||
let mut i = 0;
|
||||
while i < crate::mem::size_of::<T>() {
|
||||
r.as_bytes_mut()[i] = crate::mem::MaybeUninit::new(0xFF);
|
||||
i += 1;
|
||||
}
|
||||
unsafe { r.assume_init() }
|
||||
};
|
||||
[zeros, ones][x as usize]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn splat(value: bool) -> Self {
|
||||
unsafe { crate::intrinsics::simd::simd_splat(value) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn as_array(&self) -> &[T; N] {
|
||||
let simd_ptr: *const Self = self;
|
||||
let array_ptr: *const [T; N] = simd_ptr.cast();
|
||||
// SAFETY: We can always read the prefix of a simd type as an array.
|
||||
// There might be more padding afterwards for some widths, but
|
||||
// that's not a problem for reading less than that.
|
||||
unsafe { &*array_ptr }
|
||||
}
|
||||
}
|
||||
|
||||
// `#[derive(Clone)]` causes ICE "Projecting into SIMD type core_arch::simd::SimdM is banned by MCP#838"
|
||||
impl<T: SimdElement, const N: usize> Clone for SimdM<T, N> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
impl<T: SimdElement, const N: usize> const crate::cmp::PartialEq for SimdM<T, N> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_array() == other.as_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SimdElement, const N: usize> crate::fmt::Debug for SimdM<T, N> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
|
||||
debug_simd_finish(f, "SimdM", self.as_array())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! simd_m_ty {
|
||||
($id:ident [$elem_type:ident ; $len:literal]: $($param_name:ident),*) => {
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct $id([$elem_type; $len]);
|
||||
pub(crate) type $id = SimdM<$elem_type, $len>;
|
||||
|
||||
#[allow(clippy::use_self)]
|
||||
impl $id {
|
||||
#[inline(always)]
|
||||
const fn bool_to_internal(x: bool) -> $elem_type {
|
||||
[0 as $elem_type, !(0 as $elem_type)][x as usize]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) const fn new($($param_name: bool),*) -> Self {
|
||||
$id([$(Self::bool_to_internal($param_name)),*])
|
||||
}
|
||||
|
||||
// FIXME: Workaround rust@60637
|
||||
#[inline(always)]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn splat(value: bool) -> Self {
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(simd)]
|
||||
struct JustOne([$elem_type; 1]);
|
||||
let one = JustOne([Self::bool_to_internal(value)]);
|
||||
// SAFETY: 0 is always in-bounds because we're shuffling
|
||||
// a simd type with exactly one element.
|
||||
unsafe { simd_shuffle!(one, one, [0; $len]) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn as_array(&self) -> &[$elem_type; $len] {
|
||||
let simd_ptr: *const Self = self;
|
||||
let array_ptr: *const [$elem_type; $len] = simd_ptr.cast();
|
||||
// SAFETY: We can always read the prefix of a simd type as an array.
|
||||
// There might be more padding afterwards for some widths, but
|
||||
// that's not a problem for reading less than that.
|
||||
unsafe { &*array_ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
const impl core::cmp::PartialEq for $id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_array() == other.as_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for $id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
debug_simd_finish(f, stringify!($id), self.as_array())
|
||||
Self([$(Self::bool_to_internal($param_name)),*])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2746,7 +2746,7 @@ pub const fn _mm256_setr_epi64x(a: i64, b: i64, c: i64, d: i64) -> __m256i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_pd(a: f64) -> __m256d {
|
||||
_mm256_setr_pd(a, a, a, a)
|
||||
f64x4::splat(a).as_m256d()
|
||||
}
|
||||
|
||||
/// Broadcasts single-precision (32-bit) floating-point value `a` to all
|
||||
|
|
@ -2759,7 +2759,7 @@ pub const fn _mm256_set1_pd(a: f64) -> __m256d {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_ps(a: f32) -> __m256 {
|
||||
_mm256_setr_ps(a, a, a, a, a, a, a, a)
|
||||
f32x8::splat(a).as_m256()
|
||||
}
|
||||
|
||||
/// Broadcasts 8-bit integer `a` to all elements of returned vector.
|
||||
|
|
@ -2772,13 +2772,7 @@ pub const fn _mm256_set1_ps(a: f32) -> __m256 {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_epi8(a: i8) -> __m256i {
|
||||
#[rustfmt::skip]
|
||||
_mm256_setr_epi8(
|
||||
a, a, a, a, a, a, a, a,
|
||||
a, a, a, a, a, a, a, a,
|
||||
a, a, a, a, a, a, a, a,
|
||||
a, a, a, a, a, a, a, a,
|
||||
)
|
||||
i8x32::splat(a).as_m256i()
|
||||
}
|
||||
|
||||
/// Broadcasts 16-bit integer `a` to all elements of returned vector.
|
||||
|
|
@ -2793,7 +2787,7 @@ pub const fn _mm256_set1_epi8(a: i8) -> __m256i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_epi16(a: i16) -> __m256i {
|
||||
_mm256_setr_epi16(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a)
|
||||
i16x16::splat(a).as_m256i()
|
||||
}
|
||||
|
||||
/// Broadcasts 32-bit integer `a` to all elements of returned vector.
|
||||
|
|
@ -2806,7 +2800,7 @@ pub const fn _mm256_set1_epi16(a: i16) -> __m256i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_epi32(a: i32) -> __m256i {
|
||||
_mm256_setr_epi32(a, a, a, a, a, a, a, a)
|
||||
i32x8::splat(a).as_m256i()
|
||||
}
|
||||
|
||||
/// Broadcasts 64-bit integer `a` to all elements of returned vector.
|
||||
|
|
@ -2821,7 +2815,7 @@ pub const fn _mm256_set1_epi32(a: i32) -> __m256i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm256_set1_epi64x(a: i64) -> __m256i {
|
||||
_mm256_setr_epi64x(a, a, a, a)
|
||||
i64x4::splat(a).as_m256i()
|
||||
}
|
||||
|
||||
/// Cast vector of type __m256d to type __m256.
|
||||
|
|
|
|||
|
|
@ -932,7 +932,7 @@ pub const fn _mm_set_ss(a: f32) -> __m128 {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm_set1_ps(a: f32) -> __m128 {
|
||||
__m128([a, a, a, a])
|
||||
f32x4::splat(a).as_m128()
|
||||
}
|
||||
|
||||
/// Alias for [`_mm_set1_ps`](fn._mm_set1_ps.html)
|
||||
|
|
@ -2079,7 +2079,7 @@ pub unsafe fn _mm_stream_ps(mem_addr: *mut f32, a: __m128) {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::core_arch::assert_eq_const as assert_eq;
|
||||
use crate::{hint::black_box, mem::transmute, ptr};
|
||||
use crate::{hint::black_box, ptr};
|
||||
use std::boxed;
|
||||
use stdarch_test::simd_test;
|
||||
|
||||
|
|
@ -2221,7 +2221,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_min_ps() {
|
||||
fn test_mm_min_ps() {
|
||||
let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
|
||||
let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
|
||||
let r = _mm_min_ps(a, b);
|
||||
|
|
@ -2234,10 +2234,10 @@ mod tests {
|
|||
// `r1` to `a` and `r2` to `b`.
|
||||
let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0);
|
||||
let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0);
|
||||
let r1: [u8; 16] = transmute(_mm_min_ps(a, b));
|
||||
let r2: [u8; 16] = transmute(_mm_min_ps(b, a));
|
||||
let a: [u8; 16] = transmute(a);
|
||||
let b: [u8; 16] = transmute(b);
|
||||
let r1 = _mm_min_ps(a, b).as_f32x4().to_bits();
|
||||
let r2 = _mm_min_ps(b, a).as_f32x4().to_bits();
|
||||
let a = a.as_f32x4().to_bits();
|
||||
let b = b.as_f32x4().to_bits();
|
||||
assert_eq!(r1, b);
|
||||
assert_eq!(r2, a);
|
||||
assert_ne!(a, b); // sanity check that -0.0 is actually present
|
||||
|
|
@ -2252,7 +2252,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_max_ps() {
|
||||
fn test_mm_max_ps() {
|
||||
let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
|
||||
let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
|
||||
let r = _mm_max_ps(a, b);
|
||||
|
|
@ -2261,67 +2261,67 @@ mod tests {
|
|||
// Check SSE-specific semantics for -0.0 handling.
|
||||
let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0);
|
||||
let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0);
|
||||
let r1: [u8; 16] = transmute(_mm_max_ps(a, b));
|
||||
let r2: [u8; 16] = transmute(_mm_max_ps(b, a));
|
||||
let a: [u8; 16] = transmute(a);
|
||||
let b: [u8; 16] = transmute(b);
|
||||
let r1 = _mm_max_ps(a, b).as_f32x4().to_bits();
|
||||
let r2 = _mm_max_ps(b, a).as_f32x4().to_bits();
|
||||
let a = a.as_f32x4().to_bits();
|
||||
let b = b.as_f32x4().to_bits();
|
||||
assert_eq!(r1, b);
|
||||
assert_eq!(r2, a);
|
||||
assert_ne!(a, b); // sanity check that -0.0 is actually present
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
const unsafe fn test_mm_and_ps() {
|
||||
let a = transmute(u32x4::splat(0b0011));
|
||||
let b = transmute(u32x4::splat(0b0101));
|
||||
const fn test_mm_and_ps() {
|
||||
let a = f32x4::from_bits(u32x4::splat(0b0011)).as_m128();
|
||||
let b = f32x4::from_bits(u32x4::splat(0b0101)).as_m128();
|
||||
let r = _mm_and_ps(*black_box(&a), *black_box(&b));
|
||||
let e = transmute(u32x4::splat(0b0001));
|
||||
let e = f32x4::from_bits(u32x4::splat(0b0001)).as_m128();
|
||||
assert_eq_m128(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
const unsafe fn test_mm_andnot_ps() {
|
||||
let a = transmute(u32x4::splat(0b0011));
|
||||
let b = transmute(u32x4::splat(0b0101));
|
||||
const fn test_mm_andnot_ps() {
|
||||
let a = f32x4::from_bits(u32x4::splat(0b0011)).as_m128();
|
||||
let b = f32x4::from_bits(u32x4::splat(0b0101)).as_m128();
|
||||
let r = _mm_andnot_ps(*black_box(&a), *black_box(&b));
|
||||
let e = transmute(u32x4::splat(0b0100));
|
||||
let e = f32x4::from_bits(u32x4::splat(0b0100)).as_m128();
|
||||
assert_eq_m128(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
const unsafe fn test_mm_or_ps() {
|
||||
let a = transmute(u32x4::splat(0b0011));
|
||||
let b = transmute(u32x4::splat(0b0101));
|
||||
const fn test_mm_or_ps() {
|
||||
let a = f32x4::from_bits(u32x4::splat(0b0011)).as_m128();
|
||||
let b = f32x4::from_bits(u32x4::splat(0b0101)).as_m128();
|
||||
let r = _mm_or_ps(*black_box(&a), *black_box(&b));
|
||||
let e = transmute(u32x4::splat(0b0111));
|
||||
let e = f32x4::from_bits(u32x4::splat(0b0111)).as_m128();
|
||||
assert_eq_m128(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
const unsafe fn test_mm_xor_ps() {
|
||||
let a = transmute(u32x4::splat(0b0011));
|
||||
let b = transmute(u32x4::splat(0b0101));
|
||||
const fn test_mm_xor_ps() {
|
||||
let a = f32x4::from_bits(u32x4::splat(0b0011)).as_m128();
|
||||
let b = f32x4::from_bits(u32x4::splat(0b0101)).as_m128();
|
||||
let r = _mm_xor_ps(*black_box(&a), *black_box(&b));
|
||||
let e = transmute(u32x4::splat(0b0110));
|
||||
let e = f32x4::from_bits(u32x4::splat(0b0110)).as_m128();
|
||||
assert_eq_m128(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpeq_ss() {
|
||||
fn test_mm_cmpeq_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(-1.0, 5.0, 6.0, 7.0);
|
||||
let r: u32x4 = transmute(_mm_cmpeq_ss(a, b));
|
||||
let e: u32x4 = transmute(_mm_setr_ps(f32::from_bits(0), 2.0, 3.0, 4.0));
|
||||
let r = _mm_cmpeq_ss(a, b).as_f32x4().to_bits();
|
||||
let e = f32x4::new(f32::from_bits(0), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(r, e);
|
||||
|
||||
let b2 = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
let r2: u32x4 = transmute(_mm_cmpeq_ss(a, b2));
|
||||
let e2: u32x4 = transmute(_mm_setr_ps(f32::from_bits(0xffffffff), 2.0, 3.0, 4.0));
|
||||
let r2 = _mm_cmpeq_ss(a, b2).as_f32x4().to_bits();
|
||||
let e2 = f32x4::new(f32::from_bits(0xffffffff), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(r2, e2);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmplt_ss() {
|
||||
fn test_mm_cmplt_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2331,21 +2331,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) < c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) < d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmplt_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmplt_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmplt_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmplt_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmplt_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmplt_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmple_ss() {
|
||||
fn test_mm_cmple_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2355,21 +2355,21 @@ mod tests {
|
|||
let c1 = !0u32; // a.extract(0) <= c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) <= d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmple_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmple_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmple_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmple_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmple_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmple_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpgt_ss() {
|
||||
fn test_mm_cmpgt_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2379,21 +2379,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) > c.extract(0)
|
||||
let d1 = 0u32; // a.extract(0) > d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpgt_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpgt_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpgt_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpgt_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpgt_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpgt_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpge_ss() {
|
||||
fn test_mm_cmpge_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2403,21 +2403,21 @@ mod tests {
|
|||
let c1 = !0u32; // a.extract(0) >= c.extract(0)
|
||||
let d1 = 0u32; // a.extract(0) >= d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpge_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpge_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpge_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpge_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpge_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpge_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpneq_ss() {
|
||||
fn test_mm_cmpneq_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2427,21 +2427,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) != c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) != d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpneq_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpneq_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpneq_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpneq_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpneq_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpneq_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnlt_ss() {
|
||||
fn test_mm_cmpnlt_ss() {
|
||||
// TODO: this test is exactly the same as for `_mm_cmpge_ss`, but there
|
||||
// must be a difference. It may have to do with behavior in the
|
||||
// presence of NaNs (signaling or quiet). If so, we should add tests
|
||||
|
|
@ -2456,21 +2456,21 @@ mod tests {
|
|||
let c1 = !0u32; // a.extract(0) >= c.extract(0)
|
||||
let d1 = 0u32; // a.extract(0) >= d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpnlt_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpnlt_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpnlt_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpnlt_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpnlt_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpnlt_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnle_ss() {
|
||||
fn test_mm_cmpnle_ss() {
|
||||
// TODO: this test is exactly the same as for `_mm_cmpgt_ss`, but there
|
||||
// must be a difference. It may have to do with behavior in the
|
||||
// presence
|
||||
|
|
@ -2485,21 +2485,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) > c.extract(0)
|
||||
let d1 = 0u32; // a.extract(0) > d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpnle_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpnle_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpnle_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpnle_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpnle_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpnle_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpngt_ss() {
|
||||
fn test_mm_cmpngt_ss() {
|
||||
// TODO: this test is exactly the same as for `_mm_cmple_ss`, but there
|
||||
// must be a difference. It may have to do with behavior in the
|
||||
// presence of NaNs (signaling or quiet). If so, we should add tests
|
||||
|
|
@ -2514,21 +2514,21 @@ mod tests {
|
|||
let c1 = !0u32; // a.extract(0) <= c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) <= d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpngt_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpngt_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpngt_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpngt_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpngt_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpngt_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnge_ss() {
|
||||
fn test_mm_cmpnge_ss() {
|
||||
// TODO: this test is exactly the same as for `_mm_cmplt_ss`, but there
|
||||
// must be a difference. It may have to do with behavior in the
|
||||
// presence of NaNs (signaling or quiet). If so, we should add tests
|
||||
|
|
@ -2543,21 +2543,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) < c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) < d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpnge_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpnge_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpnge_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpnge_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpnge_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpnge_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpord_ss() {
|
||||
fn test_mm_cmpord_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2567,21 +2567,21 @@ mod tests {
|
|||
let c1 = 0u32; // a.extract(0) ord c.extract(0)
|
||||
let d1 = !0u32; // a.extract(0) ord d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpord_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpord_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpord_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpord_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpord_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpord_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpunord_ss() {
|
||||
fn test_mm_cmpunord_ss() {
|
||||
let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
|
||||
let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0);
|
||||
|
|
@ -2591,160 +2591,160 @@ mod tests {
|
|||
let c1 = !0u32; // a.extract(0) unord c.extract(0)
|
||||
let d1 = 0u32; // a.extract(0) unord d.extract(0)
|
||||
|
||||
let rb: u32x4 = transmute(_mm_cmpunord_ss(a, b));
|
||||
let eb: u32x4 = transmute(_mm_setr_ps(f32::from_bits(b1), 2.0, 3.0, 4.0));
|
||||
let rb = _mm_cmpunord_ss(a, b).as_f32x4().to_bits();
|
||||
let eb = f32x4::new(f32::from_bits(b1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rb, eb);
|
||||
|
||||
let rc: u32x4 = transmute(_mm_cmpunord_ss(a, c));
|
||||
let ec: u32x4 = transmute(_mm_setr_ps(f32::from_bits(c1), 2.0, 3.0, 4.0));
|
||||
let rc = _mm_cmpunord_ss(a, c).as_f32x4().to_bits();
|
||||
let ec = f32x4::new(f32::from_bits(c1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rc, ec);
|
||||
|
||||
let rd: u32x4 = transmute(_mm_cmpunord_ss(a, d));
|
||||
let ed: u32x4 = transmute(_mm_setr_ps(f32::from_bits(d1), 2.0, 3.0, 4.0));
|
||||
let rd = _mm_cmpunord_ss(a, d).as_f32x4().to_bits();
|
||||
let ed = f32x4::new(f32::from_bits(d1), 2.0, 3.0, 4.0).to_bits();
|
||||
assert_eq!(rd, ed);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpeq_ps() {
|
||||
fn test_mm_cmpeq_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, fls, tru, fls);
|
||||
let r: u32x4 = transmute(_mm_cmpeq_ps(a, b));
|
||||
let r = _mm_cmpeq_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmplt_ps() {
|
||||
fn test_mm_cmplt_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, fls, fls, fls);
|
||||
let r: u32x4 = transmute(_mm_cmplt_ps(a, b));
|
||||
let r = _mm_cmplt_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmple_ps() {
|
||||
fn test_mm_cmple_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, 4.0);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, fls, tru, fls);
|
||||
let r: u32x4 = transmute(_mm_cmple_ps(a, b));
|
||||
let r = _mm_cmple_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpgt_ps() {
|
||||
fn test_mm_cmpgt_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, tru, fls, fls);
|
||||
let r: u32x4 = transmute(_mm_cmpgt_ps(a, b));
|
||||
let r = _mm_cmpgt_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpge_ps() {
|
||||
fn test_mm_cmpge_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, tru, tru, fls);
|
||||
let r: u32x4 = transmute(_mm_cmpge_ps(a, b));
|
||||
let r = _mm_cmpge_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpneq_ps() {
|
||||
fn test_mm_cmpneq_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, tru, fls, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpneq_ps(a, b));
|
||||
let r = _mm_cmpneq_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnlt_ps() {
|
||||
fn test_mm_cmpnlt_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, tru, tru, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpnlt_ps(a, b));
|
||||
let r = _mm_cmpnlt_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnle_ps() {
|
||||
fn test_mm_cmpnle_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, tru, fls, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpnle_ps(a, b));
|
||||
let r = _mm_cmpnle_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpngt_ps() {
|
||||
fn test_mm_cmpngt_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, fls, tru, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpngt_ps(a, b));
|
||||
let r = _mm_cmpngt_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpnge_ps() {
|
||||
fn test_mm_cmpnge_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
|
||||
let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, fls, fls, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpnge_ps(a, b));
|
||||
let r = _mm_cmpnge_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpord_ps() {
|
||||
fn test_mm_cmpord_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, NAN, NAN);
|
||||
let b = _mm_setr_ps(15.0, NAN, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(tru, fls, fls, fls);
|
||||
let r: u32x4 = transmute(_mm_cmpord_ps(a, b));
|
||||
let r = _mm_cmpord_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse")]
|
||||
unsafe fn test_mm_cmpunord_ps() {
|
||||
fn test_mm_cmpunord_ps() {
|
||||
let a = _mm_setr_ps(10.0, 50.0, NAN, NAN);
|
||||
let b = _mm_setr_ps(15.0, NAN, 1.0, NAN);
|
||||
let tru = !0u32;
|
||||
let fls = 0u32;
|
||||
|
||||
let e = u32x4::new(fls, tru, tru, tru);
|
||||
let r: u32x4 = transmute(_mm_cmpunord_ps(a, b));
|
||||
let r = _mm_cmpunord_ps(a, b).as_f32x4().to_bits();
|
||||
assert_eq!(r, e);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1176,7 +1176,7 @@ pub const fn _mm_set_epi8(
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm_set1_epi64x(a: i64) -> __m128i {
|
||||
_mm_set_epi64x(a, a)
|
||||
i64x2::splat(a).as_m128i()
|
||||
}
|
||||
|
||||
/// Broadcasts 32-bit integer `a` to all elements.
|
||||
|
|
@ -1188,7 +1188,7 @@ pub const fn _mm_set1_epi64x(a: i64) -> __m128i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm_set1_epi32(a: i32) -> __m128i {
|
||||
_mm_set_epi32(a, a, a, a)
|
||||
i32x4::splat(a).as_m128i()
|
||||
}
|
||||
|
||||
/// Broadcasts 16-bit integer `a` to all elements.
|
||||
|
|
@ -1200,7 +1200,7 @@ pub const fn _mm_set1_epi32(a: i32) -> __m128i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm_set1_epi16(a: i16) -> __m128i {
|
||||
_mm_set_epi16(a, a, a, a, a, a, a, a)
|
||||
i16x8::splat(a).as_m128i()
|
||||
}
|
||||
|
||||
/// Broadcasts 8-bit integer `a` to all elements.
|
||||
|
|
@ -1212,7 +1212,7 @@ pub const fn _mm_set1_epi16(a: i16) -> __m128i {
|
|||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")]
|
||||
pub const fn _mm_set1_epi8(a: i8) -> __m128i {
|
||||
_mm_set_epi8(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a)
|
||||
i8x16::splat(a).as_m128i()
|
||||
}
|
||||
|
||||
/// Sets packed 32-bit integers with the supplied values in reverse order.
|
||||
|
|
@ -3280,11 +3280,7 @@ mod tests {
|
|||
core_arch::{simd::*, x86::*},
|
||||
hint::black_box,
|
||||
};
|
||||
use std::{
|
||||
boxed, f32, f64,
|
||||
mem::{self, transmute},
|
||||
ptr,
|
||||
};
|
||||
use std::{boxed, f32, f64, mem, ptr};
|
||||
use stdarch_test::simd_test;
|
||||
|
||||
const NAN: f64 = f64::NAN;
|
||||
|
|
@ -4593,38 +4589,38 @@ mod tests {
|
|||
}
|
||||
|
||||
#[simd_test(enable = "sse2")]
|
||||
const unsafe fn test_mm_and_pd() {
|
||||
let a = transmute(u64x2::splat(5));
|
||||
let b = transmute(u64x2::splat(3));
|
||||
const fn test_mm_and_pd() {
|
||||
let a = f64x2::from_bits(u64x2::splat(5)).as_m128d();
|
||||
let b = f64x2::from_bits(u64x2::splat(3)).as_m128d();
|
||||
let r = _mm_and_pd(a, b);
|
||||
let e = transmute(u64x2::splat(1));
|
||||
let e = f64x2::from_bits(u64x2::splat(1)).as_m128d();
|
||||
assert_eq_m128d(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse2")]
|
||||
const unsafe fn test_mm_andnot_pd() {
|
||||
let a = transmute(u64x2::splat(5));
|
||||
let b = transmute(u64x2::splat(3));
|
||||
const fn test_mm_andnot_pd() {
|
||||
let a = f64x2::from_bits(u64x2::splat(5)).as_m128d();
|
||||
let b = f64x2::from_bits(u64x2::splat(3)).as_m128d();
|
||||
let r = _mm_andnot_pd(a, b);
|
||||
let e = transmute(u64x2::splat(2));
|
||||
let e = f64x2::from_bits(u64x2::splat(2)).as_m128d();
|
||||
assert_eq_m128d(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse2")]
|
||||
const unsafe fn test_mm_or_pd() {
|
||||
let a = transmute(u64x2::splat(5));
|
||||
let b = transmute(u64x2::splat(3));
|
||||
const fn test_mm_or_pd() {
|
||||
let a = f64x2::from_bits(u64x2::splat(5)).as_m128d();
|
||||
let b = f64x2::from_bits(u64x2::splat(3)).as_m128d();
|
||||
let r = _mm_or_pd(a, b);
|
||||
let e = transmute(u64x2::splat(7));
|
||||
let e = f64x2::from_bits(u64x2::splat(7)).as_m128d();
|
||||
assert_eq_m128d(r, e);
|
||||
}
|
||||
|
||||
#[simd_test(enable = "sse2")]
|
||||
const unsafe fn test_mm_xor_pd() {
|
||||
let a = transmute(u64x2::splat(5));
|
||||
let b = transmute(u64x2::splat(3));
|
||||
const fn test_mm_xor_pd() {
|
||||
let a = f64x2::from_bits(u64x2::splat(5)).as_m128d();
|
||||
let b = f64x2::from_bits(u64x2::splat(3)).as_m128d();
|
||||
let r = _mm_xor_pd(a, b);
|
||||
let e = transmute(u64x2::splat(6));
|
||||
let e = f64x2::from_bits(u64x2::splat(6)).as_m128d();
|
||||
assert_eq_m128d(r, e);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,38 +78,45 @@ pub(crate) const fn assert_eq_m512h(a: __m512h, b: __m512h) {
|
|||
}
|
||||
|
||||
#[target_feature(enable = "sse2")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m128d(a: __m128d, idx: usize) -> f64 {
|
||||
a.as_f64x2().extract(idx)
|
||||
a.as_f64x2().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "sse")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m128(a: __m128, idx: usize) -> f32 {
|
||||
a.as_f32x4().extract(idx)
|
||||
a.as_f32x4().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m256d(a: __m256d, idx: usize) -> f64 {
|
||||
a.as_f64x4().extract(idx)
|
||||
a.as_f64x4().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m256(a: __m256, idx: usize) -> f32 {
|
||||
a.as_f32x8().extract(idx)
|
||||
a.as_f32x8().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx512f")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m512(a: __m512, idx: usize) -> f32 {
|
||||
a.as_f32x16().extract(idx)
|
||||
a.as_f32x16().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx512f")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m512d(a: __m512d, idx: usize) -> f64 {
|
||||
a.as_f64x8().extract(idx)
|
||||
a.as_f64x8().extract_dyn(idx)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx512f")]
|
||||
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
|
||||
pub(crate) const fn get_m512i(a: __m512i, idx: usize) -> i64 {
|
||||
a.as_i64x8().extract(idx)
|
||||
a.as_i64x8().extract_dyn(idx)
|
||||
}
|
||||
|
||||
// not actually an intrinsic but useful in various tests as we ported from
|
||||
|
|
|
|||
|
|
@ -59,6 +59,3 @@ vluti4q_laneq_u8
|
|||
|
||||
# Broken in Clang
|
||||
vcvth_s16_f16
|
||||
# FIXME: Broken output due to missing f16 printing support in Rust, see git blame for this line
|
||||
vmulh_lane_f16
|
||||
vmulh_laneq_f16
|
||||
|
|
|
|||
|
|
@ -100,6 +100,3 @@ vluti4q_laneq_u8
|
|||
|
||||
# Broken in Clang
|
||||
vcvth_s16_f16
|
||||
# FIXME: Broken output due to missing f16 printing support in Rust
|
||||
vmulh_lane_f16
|
||||
vmulh_laneq_f16
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@ pub fn simd_test(
|
|||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
|
||||
|
||||
let target = env::var("TARGET").expect(
|
||||
"TARGET environment variable should be set for rustc (e.g. TARGET=x86_64-apple-darwin cargo test)"
|
||||
);
|
||||
let target_arch = target
|
||||
.split('-')
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("target triple contained no \"-\": {target}"));
|
||||
|
||||
let (target_features, target_feature_attr) = match &tokens[..] {
|
||||
[] => (Vec::new(), TokenStream::new()),
|
||||
[
|
||||
|
|
@ -24,13 +33,20 @@ pub fn simd_test(
|
|||
TokenTree::Punct(equals),
|
||||
TokenTree::Literal(literal),
|
||||
] if enable == "enable" && equals.as_char() == '=' => {
|
||||
let enable_feature = literal.to_string();
|
||||
let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
|
||||
let mut enable_feature = literal
|
||||
.to_string()
|
||||
.trim_start_matches('"')
|
||||
.trim_end_matches('"')
|
||||
.to_string();
|
||||
let target_features: Vec<_> = enable_feature
|
||||
.replace('+', "")
|
||||
.split(',')
|
||||
.map(String::from)
|
||||
.collect();
|
||||
// Allows using `#[simd_test(enable = "neon")]` on aarch64/armv7 shared tests.
|
||||
if target_arch == "armv7" && target_features.iter().any(|feat| feat == "neon") {
|
||||
enable_feature.push_str(",v7");
|
||||
}
|
||||
|
||||
(
|
||||
target_features,
|
||||
|
|
@ -46,14 +62,7 @@ pub fn simd_test(
|
|||
let item_attrs = std::mem::take(&mut item.attrs);
|
||||
let name = &item.sig.ident;
|
||||
|
||||
let target = env::var("TARGET").expect(
|
||||
"TARGET environment variable should be set for rustc (e.g. TARGET=x86_64-apple-darwin cargo test)"
|
||||
);
|
||||
let macro_test = match target
|
||||
.split('-')
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("target triple contained no \"-\": {target}"))
|
||||
{
|
||||
let macro_test = match target_arch {
|
||||
"i686" | "x86_64" | "i586" => "is_x86_feature_detected",
|
||||
"arm" | "armv7" | "thumbv7neon" => "is_arm_feature_detected",
|
||||
"aarch64" | "arm64ec" | "aarch64_be" => "is_aarch64_feature_detected",
|
||||
|
|
@ -85,10 +94,20 @@ pub fn simd_test(
|
|||
|
||||
let mut detect_missing_features = TokenStream::new();
|
||||
for feature in target_features {
|
||||
let q = quote_spanned! {
|
||||
proc_macro2::Span::call_site() =>
|
||||
if !::std::arch::#macro_test!(#feature) {
|
||||
missing_features.push(#feature);
|
||||
let q = if target_arch == "armv7" && feature == "fp16" {
|
||||
// "fp16" cannot be checked at runtime
|
||||
quote_spanned! {
|
||||
proc_macro2::Span::call_site() =>
|
||||
if !cfg!(target_feature = #feature) {
|
||||
missing_features.push(#feature);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {
|
||||
proc_macro2::Span::call_site() =>
|
||||
if !::std::arch::#macro_test!(#feature) {
|
||||
missing_features.push(#feature);
|
||||
}
|
||||
}
|
||||
};
|
||||
q.to_tokens(&mut detect_missing_features);
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ neon-unstable-f16: &neon-unstable-f16
|
|||
neon-unstable-feat-lut: &neon-unstable-feat-lut
|
||||
FnCall: [unstable, ['feature = "stdarch_neon_feat_lut"', 'issue = "138050"']]
|
||||
|
||||
aarch64-unstable-jscvt: &aarch64-unstable-jscvt
|
||||
FnCall: [unstable, ['feature = "stdarch_aarch64_jscvt"', 'issue = "147555"']]
|
||||
aarch64-stable-jscvt: &aarch64-stable-jscvt
|
||||
FnCall: [stable, ['feature = "stdarch_aarch64_jscvt"', 'since = "CURRENT_RUSTC_VERSION"']]
|
||||
|
||||
# #[cfg(target_endian = "little")]
|
||||
little-endian: &little-endian
|
||||
|
|
@ -14275,7 +14275,7 @@ intrinsics:
|
|||
attr:
|
||||
- FnCall: [target_feature, ['enable = "jsconv"']]
|
||||
- FnCall: [cfg_attr, [test, { FnCall: [assert_instr, ["fjcvtzs"]] }]]
|
||||
- *aarch64-unstable-jscvt
|
||||
- *aarch64-stable-jscvt
|
||||
safety: safe
|
||||
types:
|
||||
- f64
|
||||
|
|
|
|||
|
|
@ -1736,7 +1736,7 @@ fn create_tokens(intrinsic: &Intrinsic, endianness: Endianness, tokens: &mut Tok
|
|||
);
|
||||
}
|
||||
|
||||
tokens.append_all(quote! { #[inline] });
|
||||
tokens.append_all(quote! { #[inline(always)] });
|
||||
|
||||
match endianness {
|
||||
Endianness::Little => tokens.append_all(quote! { #[cfg(target_endian = "little")] }),
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
48622726c4a91c87bf6cd4dbe1000c95df59906e
|
||||
873d4682c7d285540b8f28bfe637006cef8918a6
|
||||
|
|
|
|||
|
|
@ -275,26 +275,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
interp_ok(Scalar::from_i32(-1)) // Return non-zero on success
|
||||
}
|
||||
|
||||
#[allow(non_snake_case, clippy::arithmetic_side_effects)]
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
fn system_time_since_windows_epoch(&self, time: &SystemTime) -> InterpResult<'tcx, Duration> {
|
||||
let this = self.eval_context_ref();
|
||||
|
||||
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
|
||||
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
|
||||
let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
|
||||
// The amount of seconds between 1601/1/1 and 1970/1/1.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/sysinfo/converting-a-time-t-value-to-a-file-time
|
||||
// (just divide by the number of 100 ns intervals per second).
|
||||
const SECONDS_TO_UNIX_EPOCH: u64 = 11_644_473_600;
|
||||
|
||||
interp_ok(system_time_to_duration(time)? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
|
||||
}
|
||||
|
||||
#[allow(non_snake_case, clippy::arithmetic_side_effects)]
|
||||
fn windows_ticks_for(&self, duration: Duration) -> InterpResult<'tcx, u64> {
|
||||
let this = self.eval_context_ref();
|
||||
// 1 interval = 100 ns.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
|
||||
const NANOS_PER_INTERVAL: u128 = 100;
|
||||
|
||||
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
|
||||
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
|
||||
let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
|
||||
|
||||
let ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
|
||||
let ticks = u64::try_from(duration.as_nanos() / NANOS_PER_INTERVAL)
|
||||
.map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;
|
||||
interp_ok(ticks)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl Expander {
|
|||
callback: Option<ProcMacroClientHandle<'_>>,
|
||||
) -> Result<TokenStream<S>, PanicMessage>
|
||||
where
|
||||
<S::Server<'a> as bridge::server::Types>::TokenStream: Default,
|
||||
<S::Server<'a> as bridge::server::Server>::TokenStream: Default,
|
||||
{
|
||||
self.inner
|
||||
.proc_macros
|
||||
|
|
|
|||
|
|
@ -30,13 +30,11 @@ pub struct RaSpanServer<'a> {
|
|||
pub callback: Option<ProcMacroClientHandle<'a>>,
|
||||
}
|
||||
|
||||
impl server::Types for RaSpanServer<'_> {
|
||||
impl server::Server for RaSpanServer<'_> {
|
||||
type TokenStream = crate::token_stream::TokenStream<Span>;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::Server for RaSpanServer<'_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
|
|
|
|||
|
|
@ -36,13 +36,11 @@ pub struct SpanIdServer<'a> {
|
|||
pub callback: Option<ProcMacroClientHandle<'a>>,
|
||||
}
|
||||
|
||||
impl server::Types for SpanIdServer<'_> {
|
||||
impl server::Server for SpanIdServer<'_> {
|
||||
type TokenStream = crate::token_stream::TokenStream<Span>;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::Server for SpanIdServer<'_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/dont-eval-const-block-during-promotion.rs:48:14
|
||||
|
|
||||
LL | x = &([0][const { 0 }] & 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
...
|
||||
LL | (x, y, z);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/dont-eval-const-block-during-promotion.rs:50:14
|
||||
|
|
||||
LL | y = &(1 / const { 1 });
|
||||
| ^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
...
|
||||
LL | (x, y, z);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/dont-eval-const-block-during-promotion.rs:52:14
|
||||
|
|
||||
LL | z = &(const { 1 } / -1);
|
||||
| ^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
LL |
|
||||
LL | (x, y, z);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
//! Test for #150464: as of #138499, trying to evaluate const blocks during constant promotion will
|
||||
//! result in a query cycle, so we shouldn't do it. Evaluation can happen when trying to promote
|
||||
//! integer division and array indexing, where it's necessary for the operation to succeed to be
|
||||
//! able to use it in a promoted constant.
|
||||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
use std::mem::offset_of;
|
||||
|
||||
struct Thing(i32);
|
||||
|
||||
fn main() {
|
||||
// For a temporary involving array indexing to be promoted, we evaluate the index to make sure
|
||||
// it's in-bounds. As of #150557 we treat inline constants as maybe-out-of-bounds to avoid the
|
||||
// query cycle from evaluating them. That allows this to compile:
|
||||
let x = &([0][const { 0 }] & 0);
|
||||
// Likewise, integer divisors must be nonzero. Avoiding the query cycle allows this to compile:
|
||||
let y = &(1 / const { 1 });
|
||||
// Likewise, signed integer dividends can't be the integer minimum when the divisor is -1.
|
||||
let z = &(const { 1 } / -1);
|
||||
// These temporaries are all lifetime-extended, so they don't need to be promoted for references
|
||||
// to them to be live later in the block. Generally, code with const blocks in these positions
|
||||
// should compile as long as being promoted isn't necessary for borrow-checking to succeed.
|
||||
(x, y, z);
|
||||
|
||||
// A reduced example from real code (#150464): this can't be promoted since the array is a local
|
||||
// variable, but it still resulted in a query cycle because the index was evaluated for the
|
||||
// bounds-check before checking that. By not evaluating the const block, we avoid the cycle.
|
||||
// Since this doesn't rely on promotion, it should borrow-check successfully.
|
||||
let temp = [0u8];
|
||||
let _ = &(temp[const { 0usize }] & 0u8);
|
||||
// #150464 was reported because `offset_of!` started desugaring to a const block in #148151.
|
||||
let _ = &(temp[offset_of!(Thing, 0)] & 0u8);
|
||||
|
||||
// Similarly, at the time #150464 was reported, the index here was evaluated before checking
|
||||
// that the indexed expression is an array. As above, this can't be promoted, but still resulted
|
||||
// in a query cycle. By not evaluating the const block, we avoid the cycle. Since this doesn't
|
||||
// rely on promotion, it should borrow-check successfully.
|
||||
let temp: &[u8] = &[0u8];
|
||||
let _ = &(temp[const { 0usize }] & 0u8);
|
||||
|
||||
// By no longer promoting these temporaries, they're dropped at the ends of their respective
|
||||
// statements, so we can't refer to them thereafter. This code no longer query-cycles, but it
|
||||
// fails to borrow-check instead.
|
||||
#[cfg(fail)]
|
||||
{
|
||||
let (x, y, z);
|
||||
x = &([0][const { 0 }] & 0);
|
||||
//[fail]~^ ERROR: temporary value dropped while borrowed
|
||||
y = &(1 / const { 1 });
|
||||
//[fail]~^ ERROR: temporary value dropped while borrowed
|
||||
z = &(const { 1 } / -1);
|
||||
//[fail]~^ ERROR: temporary value dropped while borrowed
|
||||
(x, y, z);
|
||||
}
|
||||
|
||||
// Sanity check: those temporaries do promote if the const blocks are removed.
|
||||
// If constant promotion is changed so that these are no longer implicitly promoted, the
|
||||
// comments on this test file should be reworded to reflect that.
|
||||
let (x, y, z);
|
||||
x = &([0][0] & 0);
|
||||
y = &(1 / 1);
|
||||
z = &(1 / -1);
|
||||
(x, y, z);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue