mirror of
https://github.com/Noratrieb/intringen.git
synced 2026-01-14 22:05:02 +01:00
generate _mm_packus_epi16
This commit is contained in:
commit
429d9b826c
13 changed files with 855 additions and 0 deletions
12
crates/generate/Cargo.toml
Normal file
12
crates/generate/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "generate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
eyre = "0.6.11"
|
||||
heck = "0.4.1"
|
||||
logos = "0.13.0"
|
||||
strong-xml = "0.6.3"
|
||||
230
crates/generate/src/generate.rs
Normal file
230
crates/generate/src/generate.rs
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
use crate::{
|
||||
parse::{Expr, Stmt},
|
||||
Intrinsic,
|
||||
};
|
||||
use eyre::{bail, Context, OptionExt, Result};
|
||||
|
||||
pub fn generate(intrinsics: &[Intrinsic]) -> Result<()> {
|
||||
println!("impl<C: super::Core> Intrinsics for C {{}}");
|
||||
println!("trait Intrinsics: super::Core {{");
|
||||
for intr in intrinsics {
|
||||
generate_intr(intr).wrap_err_with(|| format!("generating `{}`", intr.name))?;
|
||||
}
|
||||
|
||||
println!("}}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_intr(intr: &Intrinsic) -> Result<(), eyre::Error> {
|
||||
let signature = signature(intr)?;
|
||||
println!(" {signature} {{");
|
||||
let body = generate_body(intr).wrap_err("generating body")?;
|
||||
println!("{}", indent(&body, 8));
|
||||
println!(" }}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn indent(input: &str, indent: usize) -> String {
|
||||
let replace = format!("\n{}", " ".repeat(indent));
|
||||
let mut s = " ".repeat(indent);
|
||||
s.push_str(&input.trim_end().replace("\n", &replace));
|
||||
s
|
||||
}
|
||||
|
||||
struct VariableType {
|
||||
is_signed: bool,
|
||||
elem_width: u64,
|
||||
#[allow(dead_code)]
|
||||
full_width: u64,
|
||||
raw_type: String,
|
||||
}
|
||||
|
||||
impl VariableType {
|
||||
fn of(etype: &str, ty: &str) -> Result<Self> {
|
||||
let full_width = match ty {
|
||||
"__m128i" => 128,
|
||||
_ => bail!("unknown type: {ty}"),
|
||||
};
|
||||
let (is_signed, elem_width) = match etype {
|
||||
"SI16" => (true, 16),
|
||||
"UI8" => (false, 8),
|
||||
_ => bail!("unknown element type: {etype}"),
|
||||
};
|
||||
Ok(Self {
|
||||
is_signed,
|
||||
full_width,
|
||||
elem_width,
|
||||
raw_type: ty.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
fn rust_type(&self) -> String {
|
||||
let pre = if self.is_signed { 'i' } else { 'u' };
|
||||
format!("{pre}{}", self.elem_width)
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_body(instr: &Intrinsic) -> Result<String> {
|
||||
let opstmts = parse_op(instr)?;
|
||||
let mut rust_stmts = Vec::<String>::new();
|
||||
|
||||
let type_of_ident = |ident: &str| -> Result<VariableType> {
|
||||
for param in &instr.parameter {
|
||||
if param.varname.as_deref() == Some(ident) {
|
||||
return VariableType::of(
|
||||
param.etype.as_deref().ok_or_eyre("no param etype")?,
|
||||
param.r#type.as_deref().ok_or_eyre("no param type")?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if instr.ret.varname.as_deref() == Some(ident) {
|
||||
return VariableType::of(
|
||||
instr.ret.etype.as_deref().ok_or_eyre("no param etype")?,
|
||||
instr.ret.r#type.as_deref().ok_or_eyre("no param type")?,
|
||||
);
|
||||
}
|
||||
|
||||
bail!("variable {ident} not found in pseudocode");
|
||||
};
|
||||
|
||||
for stmt in opstmts {
|
||||
match stmt {
|
||||
Stmt::Assign { lhs, rhs } => {
|
||||
let Expr::Index { lhs, idx } = lhs else {
|
||||
bail!("lhs of assign must be indexing");
|
||||
};
|
||||
let Expr::Ident(ident) = *lhs else {
|
||||
bail!("lhs of indexing must be identifier");
|
||||
};
|
||||
let Expr::Range { left, right } = *idx else {
|
||||
bail!("idx argument must be range");
|
||||
};
|
||||
let Expr::Int(high) = *left else {
|
||||
bail!("lhs of range must be int");
|
||||
};
|
||||
let Expr::Int(low) = *right else {
|
||||
bail!("rhs of range must be int");
|
||||
};
|
||||
if high < low {
|
||||
bail!("range must be HIGH:LOW, but was {high}:{low}");
|
||||
}
|
||||
|
||||
let size = high - low + 1; // (inclusive)
|
||||
if !size.is_power_of_two() {
|
||||
bail!("indexing size must be power of two");
|
||||
}
|
||||
|
||||
let ty = type_of_ident(&ident)?;
|
||||
if size != ty.elem_width {
|
||||
bail!(
|
||||
"unsupported not-direct element indexing, size={size}, element size={}",
|
||||
ty.elem_width
|
||||
);
|
||||
}
|
||||
let expr = generate_expr_tmp(&mut rust_stmts, rhs, &type_of_ident)?;
|
||||
let raw = &ty.raw_type;
|
||||
let rust_type = ty.rust_type();
|
||||
let lane_idx = low / ty.elem_width;
|
||||
rust_stmts.push(format!(
|
||||
"self.set_lane_{raw}_{rust_type}({ident}, {lane_idx}, {expr});"
|
||||
));
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(rust_stmts.join("\n"))
|
||||
}
|
||||
|
||||
fn generate_expr_tmp(
|
||||
rust_stmts: &mut Vec<String>,
|
||||
expr: Expr,
|
||||
type_of_ident: &impl Fn(&str) -> Result<VariableType>,
|
||||
) -> Result<String> {
|
||||
let result = match expr {
|
||||
Expr::Int(int) => int.to_string(),
|
||||
Expr::Ident(_) => todo!(),
|
||||
Expr::Index { lhs, idx } => {
|
||||
let Expr::Ident(ident) = *lhs else {
|
||||
bail!("lhs of indexing must be identifier");
|
||||
};
|
||||
let Expr::Range { left, right } = *idx else {
|
||||
bail!("idx argument must be range");
|
||||
};
|
||||
let Expr::Int(high) = *left else {
|
||||
bail!("lhs of range must be int");
|
||||
};
|
||||
let Expr::Int(low) = *right else {
|
||||
bail!("rhs of range must be int");
|
||||
};
|
||||
if high < low {
|
||||
bail!("range must be HIGH:LOW, but was {high}:{low}");
|
||||
}
|
||||
let size = high - low + 1; // (inclusive)
|
||||
if !size.is_power_of_two() {
|
||||
bail!("indexing size must be power of two");
|
||||
}
|
||||
|
||||
let ty = type_of_ident(&ident)?;
|
||||
if size != ty.elem_width {
|
||||
bail!(
|
||||
"unsupported not-direct element indexing, size={size}, element size={}",
|
||||
ty.elem_width
|
||||
);
|
||||
}
|
||||
let raw = &ty.raw_type;
|
||||
let rust_type = ty.rust_type();
|
||||
let lane_idx = low / ty.elem_width;
|
||||
let stmt = format!("let __tmp = self.get_lane_{raw}_{rust_type}({ident}, {lane_idx});");
|
||||
rust_stmts.push(stmt);
|
||||
"__tmp".into()
|
||||
}
|
||||
Expr::Range { .. } => todo!(),
|
||||
Expr::Call { function, args } => {
|
||||
let function = heck::AsSnekCase(function);
|
||||
let args = args
|
||||
.into_iter()
|
||||
.map(|arg| generate_expr_tmp(rust_stmts, arg, type_of_ident))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.join(", ");
|
||||
let stmt = format!("let __tmp = self.{function}({args});");
|
||||
rust_stmts.push(stmt);
|
||||
"__tmp".into()
|
||||
}
|
||||
Expr::BinaryOp { .. } => todo!(),
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn parse_op(intr: &Intrinsic) -> Result<Vec<Stmt>> {
|
||||
let Some(operation) = &intr.operation else {
|
||||
bail!("intrinsic {} has no operation", intr.name);
|
||||
};
|
||||
let stmts = crate::parse::parse_operation(&operation.value).wrap_err("parsing intrinsic")?;
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
fn signature(intr: &Intrinsic) -> Result<String> {
|
||||
let name = &intr.name;
|
||||
|
||||
let args = intr
|
||||
.parameter
|
||||
.iter()
|
||||
.map(|param| {
|
||||
format!(
|
||||
"{}: Self::{}",
|
||||
param.varname.as_ref().unwrap(),
|
||||
param.r#type.as_ref().unwrap()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
let ret_name = intr.ret.varname.as_ref().unwrap();
|
||||
let ret_ty = intr.ret.r#type.as_ref().unwrap();
|
||||
|
||||
Ok(format!(
|
||||
"fn {name}(&mut self, {ret_name}: &mut Self::{ret_ty}, {args})"
|
||||
))
|
||||
}
|
||||
87
crates/generate/src/main.rs
Normal file
87
crates/generate/src/main.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
mod generate;
|
||||
mod parse;
|
||||
|
||||
use eyre::{Context, Result};
|
||||
use strong_xml::XmlRead;
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "intrinsics_list")]
|
||||
struct IntrinsicsList {
|
||||
#[xml(child = "intrinsic")]
|
||||
intrinsics: Vec<Intrinsic>,
|
||||
}
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "intrinsic")]
|
||||
struct Intrinsic {
|
||||
#[xml(attr = "name")]
|
||||
name: String,
|
||||
#[xml(child = "return")]
|
||||
ret: Return,
|
||||
#[xml(child = "parameter")]
|
||||
parameter: Vec<Parameter>,
|
||||
#[xml(child = "operation")]
|
||||
operation: Option<Operation>,
|
||||
#[xml(child = "CPUID")]
|
||||
cpuid: Vec<CpuId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "return")]
|
||||
struct Return {
|
||||
/// Element type
|
||||
#[xml(attr = "etype")]
|
||||
etype: Option<String>,
|
||||
#[xml(attr = "type")]
|
||||
r#type: Option<String>,
|
||||
#[xml(attr = "varname")]
|
||||
varname: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "parameter")]
|
||||
struct Parameter {
|
||||
/// Element type
|
||||
#[xml(attr = "etype")]
|
||||
etype: Option<String>,
|
||||
#[xml(attr = "type")]
|
||||
r#type: Option<String>,
|
||||
#[xml(attr = "varname")]
|
||||
varname: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "operation")]
|
||||
struct Operation {
|
||||
#[xml(text)]
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, XmlRead)]
|
||||
#[xml(tag = "CPUID")]
|
||||
struct CpuId {
|
||||
#[xml(text)]
|
||||
value: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let data = std::fs::read_to_string("intrinsics.xml")
|
||||
.wrap_err("unable to find intrinsics.xml, get the file from the intel intrinsics guide")?;
|
||||
|
||||
let IntrinsicsList { intrinsics: list } =
|
||||
IntrinsicsList::from_str(&data).wrap_err("failed to parse intrinsics.xml")?;
|
||||
|
||||
eprintln!("loaded {} intrinsics", list.len());
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.filter(|intr| intr.cpuid.iter().any(|cpu| !cpu.value.contains("AVX512")))
|
||||
.filter(|intr| intr.name == "_mm_packus_epi16")
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
eprintln!("filtered: {}", list.len());
|
||||
|
||||
generate::generate(&list).wrap_err("generating rust code")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
215
crates/generate/src/parse.rs
Normal file
215
crates/generate/src/parse.rs
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
use eyre::{bail, ContextCompat, OptionExt, Result};
|
||||
use logos::Logos;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Stmt {
|
||||
FnDef,
|
||||
Assign {
|
||||
lhs: Expr,
|
||||
rhs: Expr,
|
||||
},
|
||||
If {
|
||||
cond: Expr,
|
||||
then: Expr,
|
||||
els: Option<Expr>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Expr {
|
||||
Int(u64),
|
||||
Ident(String),
|
||||
Index {
|
||||
lhs: Box<Expr>,
|
||||
idx: Box<Expr>,
|
||||
},
|
||||
Range {
|
||||
left: Box<Expr>,
|
||||
right: Box<Expr>,
|
||||
},
|
||||
Call {
|
||||
function: String,
|
||||
args: Vec<Expr>,
|
||||
},
|
||||
BinaryOp {
|
||||
op: BinaryOpKind,
|
||||
lhs: Box<Expr>,
|
||||
rhs: Box<Expr>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum BinaryOpKind {}
|
||||
|
||||
pub(crate) fn parse_operation(op: &str) -> Result<Vec<Stmt>> {
|
||||
let tokens = Token::lexer(op.trim())
|
||||
.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.map_err(|()| eyre::eyre!("failed to lex"))?;
|
||||
let stmts = parse(tokens)?;
|
||||
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
struct Parser {
|
||||
tokens: std::iter::Peekable<std::vec::IntoIter<Token>>,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
fn next(&mut self) -> Result<Token> {
|
||||
self.tokens.next().ok_or_eyre("reached EOF")
|
||||
}
|
||||
fn peek(&mut self) -> Result<&Token> {
|
||||
self.tokens.peek().ok_or_eyre("reached EOF")
|
||||
}
|
||||
fn expect(&mut self, token: Token) -> Result<()> {
|
||||
let n = self.next()?;
|
||||
if n != token {
|
||||
bail!("expected {token:?}, found {n:?}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn eat(&mut self, token: Token) -> bool {
|
||||
if self.tokens.peek() == Some(&token) {
|
||||
self.tokens.next();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(tokens: Vec<Token>) -> Result<Vec<Stmt>> {
|
||||
let parser = &mut Parser {
|
||||
tokens: tokens.into_iter().peekable(),
|
||||
};
|
||||
let mut stmts = Vec::new();
|
||||
|
||||
while parser.tokens.peek().is_some() {
|
||||
let stmt = parse_stmt(parser)?;
|
||||
stmts.push(stmt);
|
||||
}
|
||||
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
fn parse_stmt(parser: &mut Parser) -> Result<Stmt> {
|
||||
let stmt = match parser.peek() {
|
||||
_ => {
|
||||
let expr = parse_expr(parser)?;
|
||||
|
||||
if parser.eat(Token::Assign) {
|
||||
let rhs = parse_expr(parser)?;
|
||||
|
||||
Stmt::Assign { lhs: expr, rhs }
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
};
|
||||
parser.eat(Token::Newline);
|
||||
Ok(stmt)
|
||||
}
|
||||
|
||||
fn parse_expr(parser: &mut Parser) -> Result<Expr> {
|
||||
parse_expr_range(parser)
|
||||
}
|
||||
|
||||
fn parse_expr_range(parser: &mut Parser) -> Result<Expr> {
|
||||
let expr = parse_expr_call(parser)?;
|
||||
if parser.eat(Token::Colon) {
|
||||
let rhs = parse_expr_call(parser)?;
|
||||
Ok(Expr::Range {
|
||||
left: Box::new(expr),
|
||||
right: Box::new(rhs),
|
||||
})
|
||||
} else {
|
||||
Ok(expr)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expr_call(parser: &mut Parser) -> Result<Expr> {
|
||||
let mut lhs = parse_expr_atom(parser)?;
|
||||
|
||||
loop {
|
||||
if parser.eat(Token::ParenOpen) {
|
||||
let arg = parse_expr(parser)?;
|
||||
parser.expect(Token::ParenClose);
|
||||
let Expr::Ident(ident) = lhs else {
|
||||
panic!("lhs of function must be ident");
|
||||
};
|
||||
lhs = Expr::Call {
|
||||
function: ident,
|
||||
args: vec![arg],
|
||||
};
|
||||
continue;
|
||||
}
|
||||
if parser.eat(Token::BracketOpen) {
|
||||
let arg = parse_expr(parser)?;
|
||||
parser.expect(Token::BracketClose);
|
||||
lhs = Expr::Index {
|
||||
lhs: Box::new(lhs),
|
||||
idx: Box::new(arg),
|
||||
};
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Ok(lhs)
|
||||
}
|
||||
|
||||
fn parse_expr_atom(parser: &mut Parser) -> Result<Expr> {
|
||||
let token = parser.next()?;
|
||||
Ok(match token {
|
||||
Token::Ident(ident) => Expr::Ident(ident),
|
||||
Token::Integer(int) => Expr::Int(int),
|
||||
_ => panic!("unexpected token in expr position: {token:?}"),
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Logos, PartialEq, Eq)]
|
||||
enum Token {
|
||||
#[regex("//[^\n]*\n?", logos::skip)]
|
||||
#[regex(r"[ \t\r]+", logos::skip)]
|
||||
Comment,
|
||||
|
||||
#[token("(")]
|
||||
ParenOpen,
|
||||
#[token("[")]
|
||||
BracketOpen,
|
||||
#[token(")")]
|
||||
ParenClose,
|
||||
#[token("]")]
|
||||
BracketClose,
|
||||
|
||||
#[token("DEFINE")]
|
||||
Define,
|
||||
#[token("CASE")]
|
||||
Case,
|
||||
#[token("ESAC")]
|
||||
Esac,
|
||||
#[token("IF")]
|
||||
If,
|
||||
#[token("FI")]
|
||||
Fi,
|
||||
#[token("RETURN")]
|
||||
Return,
|
||||
#[token("OF")]
|
||||
Of,
|
||||
|
||||
#[token("\n")]
|
||||
Newline,
|
||||
|
||||
#[token(",")]
|
||||
Comma,
|
||||
#[token(":=")]
|
||||
Assign,
|
||||
#[token(":")]
|
||||
Colon,
|
||||
|
||||
#[regex(r"[a-zA-Z_]\w*", |lex| lex.slice().to_owned())]
|
||||
Ident(String),
|
||||
|
||||
#[regex(r"\d+", |lex| lex.slice().parse().ok())]
|
||||
Integer(u64),
|
||||
}
|
||||
8
crates/intringen/Cargo.toml
Normal file
8
crates/intringen/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "intringen"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
3
crates/intringen/src/lib.rs
Normal file
3
crates/intringen/src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub mod x86;
|
||||
|
||||
pub trait Lanes<const N: usize, Elem> {}
|
||||
53
crates/intringen/src/x86/generated.rs
Normal file
53
crates/intringen/src/x86/generated.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
impl<C: super::Core> Intrinsics for C {}
|
||||
trait Intrinsics: super::Core {
|
||||
fn _mm_packus_epi16(&mut self, dst: &mut Self::__m128i, a: Self::__m128i, b: Self::__m128i) {
|
||||
let __tmp = self.get_lane___m128i_i16(a, 0);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 0, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 1);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 1, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 2);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 2, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 3);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 3, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 4);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 4, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 5);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 5, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 6);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 6, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(a, 7);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 7, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 0);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 8, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 1);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 9, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 2);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 10, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 3);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 11, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 4);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 12, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 5);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 13, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 6);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 14, __tmp);
|
||||
let __tmp = self.get_lane___m128i_i16(b, 7);
|
||||
let __tmp = self.saturate_u8(__tmp);
|
||||
self.set_lane___m128i_u8(dst, 15, __tmp);
|
||||
}
|
||||
}
|
||||
49
crates/intringen/src/x86/mod.rs
Normal file
49
crates/intringen/src/x86/mod.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#![allow(non_camel_case_types, non_snake_case)]
|
||||
|
||||
mod generated;
|
||||
|
||||
pub trait Core {
|
||||
type __m128i: Copy;
|
||||
|
||||
fn get_lane___m128i_u16(&mut self, value: Self::__m128i, idx: u64) -> u16;
|
||||
fn get_lane___m128i_i16(&mut self, value: Self::__m128i, idx: u64) -> i16;
|
||||
|
||||
fn set_lane___m128i_u8(&mut self, place: &mut Self::__m128i, idx: u64, value: u8);
|
||||
fn set_lane___m128i_i8(&mut self, place: &mut Self::__m128i, idx: u64, value: i8);
|
||||
|
||||
fn saturate_u8(&mut self, elem: i16) -> u8;
|
||||
}
|
||||
|
||||
pub struct ValueCore;
|
||||
|
||||
impl Core for ValueCore {
|
||||
type __m128i = [u8; 16];
|
||||
|
||||
fn get_lane___m128i_u16(&mut self, value: Self::__m128i, idx: u64) -> u16 {
|
||||
let first = value[(idx * 2) as usize];
|
||||
let second = value[(idx * 2 + 1) as usize];
|
||||
// todo: le? be?
|
||||
((first << 8) as u16) | (second as u16)
|
||||
}
|
||||
|
||||
fn get_lane___m128i_i16(&mut self, value: Self::__m128i, idx: u64) -> i16 {
|
||||
let first = value[(idx * 2) as usize];
|
||||
let second = value[(idx * 2 + 1) as usize];
|
||||
// todo: le? be?
|
||||
(((first << 8) as u16) | (second as u16)) as i16
|
||||
}
|
||||
|
||||
fn set_lane___m128i_u8(&mut self, place: &mut Self::__m128i, idx: u64, value: u8) {
|
||||
place[idx as usize] = value;
|
||||
}
|
||||
|
||||
fn set_lane___m128i_i8(&mut self, place: &mut Self::__m128i, idx: u64, value: i8) {
|
||||
place[idx as usize] = value as u8;
|
||||
}
|
||||
|
||||
fn saturate_u8(&mut self, elem: i16) -> u8 {
|
||||
let clamp = elem.clamp(0, u8::MAX as i16);
|
||||
clamp as u8
|
||||
}
|
||||
}
|
||||
pub trait Lanes<const N: usize, Elem> {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue