macro_rules! const_assert {
(<$($gname:ident $(: $gtype:path)?),*> $cond:expr) => { {
const fn assert<$($gname $(: $gtype)?),*>() {
assert!($cond);
}
const { assert::<$($gname),*>() }
} };
($cond:expr) => { {
const fn assert(cond: bool) {
assert!(cond);
}
const { assert($cond) }
} };
}
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! 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! translate_simd_inner_params {
( // Transcribe one 'self' parameter.
$group:ty, $array:ty,
($self:ident => $this:ident $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
unsafe fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)?
where $($bname:ty: $bound:path),+
$body:block
}
) => {
translate_simd_inner_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
unsafe fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $this: Vector<$array, $group, FS>,)
$(-> $rett)?
where $($bname: $bound),+
$body
});
};
( $group:ty, $array:ty,
($hname:ident: Self $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
unsafe fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)?
where $($bname:ty: $bound:path),+
$body:block
}
) => {
translate_simd_inner_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
unsafe fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $hname: Vector<$array, $group, FS>,)
$(-> $rett)?
where $($bname: $bound),+
$body
});
};
( $group:ty, $array:ty,
($hname:ident: Self $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
unsafe fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)?
where $($bname:ty: $bound:path),+
$body:block
}
) => {
translate_simd_inner_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
unsafe fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $hname: Vector<$array, $group, FS>,)
$(-> $rett)?
where $($bname: $bound),+
$body
});
};
( $group:ty, $array:ty,
($hname:ident: $htype:ty $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
unsafe fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)?
where $($bname:ty: $bound:path),+
$body:block
}
) => {
translate_simd_inner_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
unsafe fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $hname: $htype,)
$(-> $rett)?
where $($bname: $bound),+
$body
});
};
( $group:ty, $array:ty, (), {
$(#[$attr:meta])*
unsafe fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),* $(,)?>)?
($($prev:tt)*) $(-> $rett:ty)?
where $($bname:ty: $bound:path),+
$body:block
}
) => {
$(#[$attr])*
unsafe fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)*) $(-> $rett)?
where $($bname: $bound),+
$body
};
}
macro_rules! translate_simd_icall_params {
( // Transcribe one 'self' parameter.
($self:ident => $this:ident $(, $($tail:tt)*)?),
$name:ident::<$($iname:ident $(: $itype:path)?),*>($($prev:tt)*)
) => {
translate_simd_icall_params!(
($($($tail)*)?),
$name::<$($iname $(: $itype)?),*>($($prev)* $self,))
};
( ($hname:ident: $htype:ty $(, $($tail:tt)*)?),
$name:ident::<$($iname:ident $(: $itype:path)?),*>($($prev:tt)*)
) => {
translate_simd_icall_params!(
($($($tail)*)?),
$name::<$($iname $(: $itype)?),*>($($prev)* $hname,))
};
( (), $name:ident::<$($iname:ident $(: $itype:path)?),*>($($prev:tt)*)
) => {
$name::<$($iname $(: $itype)?),*>($($prev)*)
};
}
macro_rules! translate_simd_outer_params {
( // Transcribe one 'self' parameter.
$group:ty, $array:ty,
($self:ident => $this:ident $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)? $body:block
}
) => {
translate_simd_outer_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $self: Self,)
$(-> $rett)? $body
});
};
( $group:ty, $array:ty,
($hname:ident: $htype:ty $(, $($tail:tt)*)?), {
$(#[$attr:meta])*
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($prev:tt)*) $(-> $rett:ty)? $body:block
}
) => {
translate_simd_outer_params!(
$group, $array, ($($($tail)*)?), {
$(#[$attr])*
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
($($prev)* $hname: $htype,)
$(-> $rett)? $body
});
};
( $group:ty, $array:ty, (), {
$(#[$attr:meta])*
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),*>)?
($($pname:ident $(: $ptype:ty)?,)*)
$(-> $rett:ty)? $body:block
}
) => {
$(#[$attr])*
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
($($pname $(: $ptype)?,)*)
$(-> $rett)? $body
};
}
macro_rules! impl_simd {
( // Transcribe a trait 'impl'.
$group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty: $trait:ty { $($body:tt)* }
) => {
impl<FS $(, $($iname $(: $itype)?),*)?>
$trait for Vector<$array, $group, FS>
where $(FS: HasFeature<$group, $feature>),+ {
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($body)* });
}
};
( $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty { $($body:tt)* }
) => {
impl<FS $(, $($iname $(: $itype)?),*)?>
Vector<$array, $group, FS>
where $(FS: HasFeature<$group, $feature>),+ {
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($body)* });
}
};
(0: $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty {
type $item:ident = $body:ty;
$($rest:tt)*
}
) => {
type $item = $body;
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($rest)* });
};
(0: $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty {
$(#[doc = $doc:literal])*
$(#[intrinsic_for($inst:literal)])?
$(#[intel_equivalents($($intel:literal),+ $(,)?)])?
$(#[cfg($cfg:meta)])?
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),* $(,)?>)?
($self:ident => $this:ident $(, $($prest:tt)*)?)
-> Self $body:block
$($rest:tt)*
}
) => {
translate_simd_outer_params!(
$group, $array, ($self => $this $(, $($prest)*)?), {
$(#[doc = $doc])*
$(#[doc = concat!("\n\nInstruction: `", $inst, "`.")])?
$(#[doc = document_intel_equivs!($($intel),+)])?
$(#[doc(alias = $inst)])?
$(#[doc(alias($($intel),+))])?
#[inline]
$(#[cfg(any(doc, $cfg))])?
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
() -> Self {
translate_simd_inner_params!(
$group, $array, ($self => $this $(, $($prest)*)?), {
#[target_feature(enable = $target)]
#[inline]
unsafe fn inner
<FS $($(, $iname $(: $itype)?)*)? $($(, $gname $(: $gtype)?)*)?>
() -> <$array as Array>::Primitive
where $(FS: HasFeature<$group, $feature>),+
$body
});
Vector::from_primitive(unsafe {
translate_simd_icall_params!(
($self => $this $(, $($prest)*)?),
inner::<FS $($(, $iname)*)? $($(, $gname)*)?>())
}).with_features($self.features)
}
});
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($rest)* });
};
(0: $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty {
$(#[doc = $doc:literal])*
$(#[intrinsic_for($inst:literal)])?
$(#[intel_equivalents($($intel:literal),+ $(,)?)])?
$(#[cfg($cfg:meta)])?
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),* $(,)?>)?
($self:ident => $this:ident $(, $($prest:tt)*)?)
$(-> $rett:ty)? $body:block
$($rest:tt)*
}
) => {
translate_simd_outer_params!(
$group, $array, ($self => $this $(, $($prest)*)?), {
$(#[doc = $doc])*
$(#[doc = concat!("\n\nInstruction: `", $inst, "`.")])?
$(#[doc = document_intel_equivs!($($intel),+)])?
$(#[doc(alias = $inst)])?
$(#[doc(alias($($intel),+))])?
#[inline]
$(#[cfg(any(doc, $cfg))])?
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
() $(-> $rett)? {
translate_simd_inner_params!(
$group, $array, ($self => $this $(, $($prest)*)?), {
#[target_feature(enable = $target)]
#[inline]
unsafe fn inner
<FS $($(, $iname $(: $itype)?)*)? $($(, $gname $(: $gtype)?)*)?>
() $(-> $rett)?
where $(FS: HasFeature<$group, $feature>),+
$body
});
unsafe {
translate_simd_icall_params!(
($self => $this $(, $($prest)*)?),
inner::<FS $($(, $iname)*)? $($(, $gname)*)?>())
}
}
});
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($rest)* });
};
(0: $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty {
$(#[doc = $doc:literal])*
$(#[intrinsic_for($inst:literal)])?
$(#[intel_equivalents($($intel:literal),+ $(,)?)])?
$(#[cfg($cfg:meta)])?
$vis:vis fn $name:ident
$(<$($gname:ident $(: $gtype:path)?),* $(,)?>)?
($($prest:tt)*) -> Self
$body:block
$($rest:tt)*
}
) => {
translate_simd_outer_params!(
$group, $array, ($($prest)*), {
$(#[doc = $doc])*
$(#[doc = concat!("\n\nInstruction: `", $inst, "`.")])?
$(#[doc = document_intel_equivs!($($intel),+)])?
$(#[doc(alias = $inst)])?
$(#[doc(alias($($intel),+))])?
#[inline]
$(#[cfg(any(doc, $cfg))])?
$vis fn $name
$(<$($gname $(: $gtype)?),*>)?
() -> Self {
translate_simd_inner_params!(
$group, $array, ($($prest)*), {
#[target_feature(enable = $target)]
#[inline]
unsafe fn inner
<FS $(, $($iname $(: $itype)?),*)?>
() -> Vector<$array, $group, FS>
where $(FS: HasFeature<$group, $feature>),+
$body
});
unsafe {
translate_simd_icall_params!(($($prest)*),
inner::<FS $($(, $iname)*)? $($(, $gname)*)?>())
}
}
});
impl_simd!(0:
$group[$($feature),+: $target]
$(<$($iname $(: $itype)?),*>)?,
$array { $($rest)* });
};
(0: $group:ty[$($feature:ty),+: $target:literal]
$(<$($iname:ident $(: $itype:path)?),* $(,)?>)?,
$array:ty { }
) => {};
}