mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-28 03:24:11 +00:00
250 lines
7.2 KiB
Rust
250 lines
7.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
|
use std::fmt;
|
|
use std::str::FromStr;
|
|
|
|
use crate::context;
|
|
use crate::expression::{Expression, FnCall, IdentifierType};
|
|
use crate::intrinsic::Intrinsic;
|
|
use crate::typekinds::{ToRepr, TypeKind};
|
|
use crate::wildcards::Wildcard;
|
|
use crate::wildstring::WildString;
|
|
|
|
const ZEROING_SUFFIX: &str = "_z";
|
|
const MERGING_SUFFIX: &str = "_m";
|
|
const DONT_CARE_SUFFIX: &str = "_x";
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(untagged)]
|
|
pub enum ZeroingMethod {
|
|
/// Drop the specified argument and replace it with a zeroinitializer
|
|
Drop { drop: WildString },
|
|
/// Apply zero selection to the specified variable when zeroing
|
|
Select { select: WildString },
|
|
}
|
|
|
|
impl PartialOrd for ZeroingMethod {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for ZeroingMethod {
|
|
fn cmp(&self, _: &Self) -> std::cmp::Ordering {
|
|
std::cmp::Ordering::Equal
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
pub enum DontCareMethod {
|
|
#[default]
|
|
Inferred,
|
|
AsZeroing,
|
|
AsMerging,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub struct PredicationMethods {
|
|
/// Zeroing method, if the zeroing predicate form is used
|
|
#[serde(default)]
|
|
pub zeroing_method: Option<ZeroingMethod>,
|
|
/// Don't care method, if the don't care predicate form is used
|
|
#[serde(default)]
|
|
pub dont_care_method: DontCareMethod,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
pub enum PredicateForm {
|
|
/// Enables merging predicate form
|
|
Merging,
|
|
/// Enables "don't care" predicate form.
|
|
DontCare(DontCareMethod),
|
|
/// Enables zeroing predicate form. If LLVM zeroselection is performed, then
|
|
/// set the `select` field to the variable that gets set. Otherwise set the
|
|
/// `drop` field if the zeroinitializer replaces a predicate when merging.
|
|
Zeroing(ZeroingMethod),
|
|
}
|
|
|
|
impl PredicateForm {
|
|
pub fn get_suffix(&self) -> &'static str {
|
|
match self {
|
|
PredicateForm::Zeroing { .. } => ZEROING_SUFFIX,
|
|
PredicateForm::Merging => MERGING_SUFFIX,
|
|
PredicateForm::DontCare { .. } => DONT_CARE_SUFFIX,
|
|
}
|
|
}
|
|
|
|
pub fn make_zeroinitializer(ty: &TypeKind) -> Expression {
|
|
FnCall::new_expression(
|
|
format!("svdup_n_{}", ty.acle_notation_repr())
|
|
.parse()
|
|
.unwrap(),
|
|
vec![if ty.base_type().unwrap().is_float() {
|
|
Expression::FloatConstant(0.0)
|
|
} else {
|
|
Expression::IntConstant(0)
|
|
}],
|
|
)
|
|
}
|
|
|
|
pub fn make_zeroselector(pg_var: WildString, op_var: WildString, ty: &TypeKind) -> Expression {
|
|
FnCall::new_expression(
|
|
format!("svsel_{}", ty.acle_notation_repr())
|
|
.parse()
|
|
.unwrap(),
|
|
vec![
|
|
Expression::Identifier(pg_var, IdentifierType::Variable),
|
|
Expression::Identifier(op_var, IdentifierType::Variable),
|
|
Self::make_zeroinitializer(ty),
|
|
],
|
|
)
|
|
}
|
|
|
|
pub fn post_build(&self, intrinsic: &mut Intrinsic) -> context::Result {
|
|
// Drop the argument
|
|
match self {
|
|
PredicateForm::Zeroing(ZeroingMethod::Drop { drop: drop_var }) => {
|
|
intrinsic.signature.drop_argument(drop_var)?
|
|
}
|
|
PredicateForm::DontCare(DontCareMethod::AsZeroing) => {
|
|
if let ZeroingMethod::Drop { drop } = intrinsic
|
|
.input
|
|
.predication_methods
|
|
.zeroing_method
|
|
.to_owned()
|
|
.ok_or_else(|| {
|
|
"DontCareMethod::AsZeroing without zeroing method.".to_string()
|
|
})?
|
|
{
|
|
intrinsic.signature.drop_argument(&drop)?
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn infer_dont_care(mask: &PredicationMask, methods: &PredicationMethods) -> PredicateForm {
|
|
let method = if methods.dont_care_method == DontCareMethod::Inferred {
|
|
if mask.has_zeroing()
|
|
&& matches!(methods.zeroing_method, Some(ZeroingMethod::Drop { .. }))
|
|
{
|
|
DontCareMethod::AsZeroing
|
|
} else {
|
|
DontCareMethod::AsMerging
|
|
}
|
|
} else {
|
|
methods.dont_care_method
|
|
};
|
|
|
|
PredicateForm::DontCare(method)
|
|
}
|
|
|
|
pub fn compile_list(
|
|
mask: &PredicationMask,
|
|
methods: &PredicationMethods,
|
|
) -> context::Result<Vec<PredicateForm>> {
|
|
let mut forms = Vec::new();
|
|
|
|
if mask.has_merging() {
|
|
forms.push(PredicateForm::Merging)
|
|
}
|
|
|
|
if mask.has_dont_care() {
|
|
forms.push(Self::infer_dont_care(mask, methods))
|
|
}
|
|
|
|
if mask.has_zeroing() {
|
|
if let Some(method) = methods.zeroing_method.to_owned() {
|
|
forms.push(PredicateForm::Zeroing(method))
|
|
} else {
|
|
return Err(
|
|
"cannot create a zeroing variant without a zeroing method specified!"
|
|
.to_string(),
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(forms)
|
|
}
|
|
}
|
|
|
|
#[derive(
|
|
Debug, Clone, Copy, Default, PartialEq, Eq, Hash, DeserializeFromStr, SerializeDisplay,
|
|
)]
|
|
pub struct PredicationMask {
|
|
/// Merging
|
|
m: bool,
|
|
/// Don't care
|
|
x: bool,
|
|
/// Zeroing
|
|
z: bool,
|
|
}
|
|
|
|
impl PredicationMask {
|
|
pub fn has_merging(&self) -> bool {
|
|
self.m
|
|
}
|
|
|
|
pub fn has_dont_care(&self) -> bool {
|
|
self.x
|
|
}
|
|
|
|
pub fn has_zeroing(&self) -> bool {
|
|
self.z
|
|
}
|
|
}
|
|
|
|
impl FromStr for PredicationMask {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let mut result = Self::default();
|
|
for kind in s.bytes() {
|
|
match kind {
|
|
b'm' => result.m = true,
|
|
b'x' => result.x = true,
|
|
b'z' => result.z = true,
|
|
_ => {
|
|
return Err(format!(
|
|
"unknown predicate form modifier: {}",
|
|
char::from(kind)
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
if result.m || result.x || result.z {
|
|
Ok(result)
|
|
} else {
|
|
Err("invalid predication mask".to_string())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for PredicationMask {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
self.m.then(|| write!(f, "m")).transpose()?;
|
|
self.x.then(|| write!(f, "x")).transpose()?;
|
|
self.z.then(|| write!(f, "z")).transpose().map(|_| ())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&WildString> for PredicationMask {
|
|
type Error = String;
|
|
|
|
fn try_from(value: &WildString) -> Result<Self, Self::Error> {
|
|
value
|
|
.wildcards()
|
|
.find_map(|w| {
|
|
if let Wildcard::PredicateForms(mask) = w {
|
|
Some(*mask)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.ok_or_else(|| "no predicate forms were specified in the name".to_string())
|
|
}
|
|
}
|