macro_rules! const_assert {
($cond:expr) => {
const fn assert(cond: bool) {
assert!(cond);
}
const { assert($cond) }
};
}
macro_rules! impl_array_vector {
(
$maker:tt ( $( ($arrays:tt [ $indices:tt ] $($cast:tt)* ), )* ),
$offset:expr, $($offsets:expr,)*
) => {
impl_array_vector!(
$maker (
$( ($arrays [ $indices ] $($cast)* ), )*
$( ($arrays [ ($offset + $indices) ] $($cast)* ), )*
),
$($offsets,)*
)
};
(
$maker:tt ( $( $value:expr, )* ),
$offset:expr, $($offsets:expr,)*
) => {
impl_array_vector!(
$maker ( $( $value, )* $( $value, )* ),
$($offsets,)*
)
};
($maker:tt ( $( $value:expr, )* ),) => {
$maker ( $( $value, )* )
};
}
macro_rules! document_intel_equivs {
($head:literal, $($tail:literal),+) => {
concat!(
"\n\nIntel Equivalents:",
document_intel_equivs!(0: $head, $($tail,)+)
)
};
($equiv:literal $(,)?) => {
concat!("\n\nIntel Equivalent: [`", $equiv, "`]")
};
(0: $head:literal, $($tail:literal,)+) => {
concat!(
" [`", $head, "`],",
document_intel_equivs!(0: $($tail,)+)
)
};
(0: $last:literal,) => {
concat!(" [`", $last, "`].",)
};
}
macro_rules! defn_simd {
{
$(#[doc = $doc:literal])*
$(#[intrinsic_for($inst:literal)])?
$(#[intel_equivalents($($intel:literal),+ $(,)?)])?
$(#[cfg($cfg:meta)])?
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
$body:block
} => {
$(#[doc = $doc])*
$(#[doc = concat!("\n\nInstruction: `", $inst, "`.")])?
$(#[doc = document_intel_equivs!($($intel),+)])?
$(#[doc(alias = $inst)])?
$(#[doc(alias($($intel),+))])?
$(#[cfg(any(doc, $cfg))])?
$vis fn $name
<
$($($imm_name: Imm<$imm_type>,)*)?
$($(const $const_name: $const_type,)*)?
>
(&self, $($param_name: $param_type),*)
$(-> $rett)? $body
};
}
macro_rules! defn_simd_body {
($target:literal, {
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
$body:block
}) => {
defn_simd! {
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*)
$(-> $rett)? {
#[inline]
#[target_feature(enable = $target)]
unsafe fn inner<
$($($imm_name: Imm<$imm_type>,)*)?
$($(const $const_name: $const_type,)*)?
>($($param_name: $param_type),*)
$(-> $rett)? $body
unsafe {
inner::<
$($($imm_name,)*)?
$($($const_name,)*)?
>($($param_name),*)
}
}
}
};
}
macro_rules! defn_simd_manual {
($target:literal, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
$body:block
)*
}) => {
$(defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*) $(-> $rett)?
$body
});)*
};
($target:literal, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
= $func:path;
)*
}) => {
$(defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*) $(-> $rett)?
{ $func($($param_name),*) }
});)*
};
}
macro_rules! defn_simd_shared {
($target:literal, $body:block, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?;
)*
}) => {
$(defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*) $(-> $rett)?
$body
});)*
};
($target:literal,
fn $param_tvars:tt -> $rett_tvar:ident $body:block,
{
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
-> $rett:ty;
)*
}) => {
$(defn_simd_shared!(0: $target, {
fn $param_tvars -> $rett_tvar $body
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*)
-> $rett;
});)*
};
(0: $target:literal, {
fn
($($param_tvar:ident),* $(,)?)
$(-> $rett_tvar:ident)?
$body:block
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
$([$($imm_name:ident: $imm_type:ty),* $(,)?])?
$(<$($const_name:ident: $const_type:ty),* $(,)?>)?
($($param_name:ident: $param_type:ty),* $(,)?)
-> $rett:ty;
}) => {
defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name
$([$($imm_name: $imm_type),*])?
$(<$($const_name: $const_type),*>)?
($($param_name: $param_type),*)
-> $rett {
$(
#[allow(dead_code)]
type $rett_tvar = $rett;
)?
$(
#[allow(dead_code)]
type $param_tvar = $param_type;
)*
$body
}
});
};
}
macro_rules! defn_simd_set_pair {
($target:literal, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
(value: [$elem:ty; 2])
-> $rett:ty;
)*
}) => {
$(defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name(value: [$elem; 2]) -> $rett {
simd_shuffle(value[0], value[1], const {
simd_slice_indices::<$rett>(0)
})
}
});)*
};
}
macro_rules! decl_llvm_func {
(
$intrinsic:literal as $name:ident
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
) => {
#[allow(improper_ctypes)]
#[allow(clashing_extern_declarations)]
extern "C" {
#[link_name = $intrinsic]
fn $name($($param_name: $param_type),*) $(-> $rett)?;
}
};
}
macro_rules! defn_simd_llvm {
($target:literal, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
= $intrinsic:literal;
)*
}) => {
$(defn_simd! {
$(#[$($attr)*])* $vis fn $name
($($param_name: $param_type),*) $(-> $rett)? {
decl_llvm_func!(
$intrinsic as
inner($($param_name: $param_type),*)
$(-> $rett)?
);
unsafe { inner($($param_name),*) }
}
})*
};
($target:literal, {
$(
$(#[$($attr:tt)*])*
$vis:vis fn $name:ident
($($param_name:ident: $param_type:ty),* $(,)?)
$(-> $rett:ty)?
= $intrinsic:literal as
$impl:ident($($impl_pname:ident: $impl_ptype:ty),*)
$(-> $impl_rett:ty)?
=> $body:block;
)*
}) => {
$(defn_simd_body!($target, {
$(#[$($attr)*])* $vis fn $name
($($param_name: $param_type),*) $(-> $rett)? {
decl_llvm_func!(
$intrinsic as
$impl($($impl_pname: $impl_ptype),*)
$(-> $impl_rett)?
);
$body
}
});)*
};
}