From 429d9b826c87923fe181806b9b761f6ed25fb6fa Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 5 Jan 2024 21:40:01 +0100 Subject: [PATCH] generate _mm_packus_epi16 --- .envrc | 1 + .gitignore | 2 + Cargo.lock | 189 +++++++++++++++++++++ Cargo.toml | 3 + crates/generate/Cargo.toml | 12 ++ crates/generate/src/generate.rs | 230 ++++++++++++++++++++++++++ crates/generate/src/main.rs | 87 ++++++++++ crates/generate/src/parse.rs | 215 ++++++++++++++++++++++++ crates/intringen/Cargo.toml | 8 + crates/intringen/src/lib.rs | 3 + crates/intringen/src/x86/generated.rs | 53 ++++++ crates/intringen/src/x86/mod.rs | 49 ++++++ shell.nix | 3 + 13 files changed, 855 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 crates/generate/Cargo.toml create mode 100644 crates/generate/src/generate.rs create mode 100644 crates/generate/src/main.rs create mode 100644 crates/generate/src/parse.rs create mode 100644 crates/intringen/Cargo.toml create mode 100644 crates/intringen/src/lib.rs create mode 100644 crates/intringen/src/x86/generated.rs create mode 100644 crates/intringen/src/x86/mod.rs create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c312b87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +intrinsics.xml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2fa2bfe --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,189 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generate" +version = "0.1.0" +dependencies = [ + "eyre", + "heck", + "logos", + "strong-xml", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "intringen" +version = "0.1.0" + +[[package]] +name = "jetscii" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "logos" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +dependencies = [ + "beef", + "fnv", + "proc-macro2", + "quote", + "regex-syntax", + "syn 2.0.46", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "proc-macro2" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "strong-xml" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d19fb3a618e2f1039e32317c9f525e6d45c55af704ec7c429aa74412419bebf" +dependencies = [ + "jetscii", + "lazy_static", + "memchr", + "strong-xml-derive", + "xmlparser", +] + +[[package]] +name = "strong-xml-derive" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c781f499321613b112be5d9338189ef1ed19689a01edd23d923ea57ad5c7e1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2ce835e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["crates/generate", "crates/intringen"] +resolver = "2" diff --git a/crates/generate/Cargo.toml b/crates/generate/Cargo.toml new file mode 100644 index 0000000..36c704e --- /dev/null +++ b/crates/generate/Cargo.toml @@ -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" diff --git a/crates/generate/src/generate.rs b/crates/generate/src/generate.rs new file mode 100644 index 0000000..2811265 --- /dev/null +++ b/crates/generate/src/generate.rs @@ -0,0 +1,230 @@ +use crate::{ + parse::{Expr, Stmt}, + Intrinsic, +}; +use eyre::{bail, Context, OptionExt, Result}; + +pub fn generate(intrinsics: &[Intrinsic]) -> Result<()> { + println!("impl 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 { + 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 { + let opstmts = parse_op(instr)?; + let mut rust_stmts = Vec::::new(); + + let type_of_ident = |ident: &str| -> Result { + 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, + expr: Expr, + type_of_ident: &impl Fn(&str) -> Result, +) -> Result { + 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::>>()? + .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> { + 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 { + 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::>() + .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})" + )) +} diff --git a/crates/generate/src/main.rs b/crates/generate/src/main.rs new file mode 100644 index 0000000..f539037 --- /dev/null +++ b/crates/generate/src/main.rs @@ -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, +} + +#[derive(Debug, XmlRead)] +#[xml(tag = "intrinsic")] +struct Intrinsic { + #[xml(attr = "name")] + name: String, + #[xml(child = "return")] + ret: Return, + #[xml(child = "parameter")] + parameter: Vec, + #[xml(child = "operation")] + operation: Option, + #[xml(child = "CPUID")] + cpuid: Vec, +} + +#[derive(Debug, XmlRead)] +#[xml(tag = "return")] +struct Return { + /// Element type + #[xml(attr = "etype")] + etype: Option, + #[xml(attr = "type")] + r#type: Option, + #[xml(attr = "varname")] + varname: Option, +} + +#[derive(Debug, XmlRead)] +#[xml(tag = "parameter")] +struct Parameter { + /// Element type + #[xml(attr = "etype")] + etype: Option, + #[xml(attr = "type")] + r#type: Option, + #[xml(attr = "varname")] + varname: Option, +} + +#[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::>(); + + eprintln!("filtered: {}", list.len()); + + generate::generate(&list).wrap_err("generating rust code")?; + + Ok(()) +} diff --git a/crates/generate/src/parse.rs b/crates/generate/src/parse.rs new file mode 100644 index 0000000..2ffeb87 --- /dev/null +++ b/crates/generate/src/parse.rs @@ -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, + }, +} + +#[derive(Debug)] +pub(crate) enum Expr { + Int(u64), + Ident(String), + Index { + lhs: Box, + idx: Box, + }, + Range { + left: Box, + right: Box, + }, + Call { + function: String, + args: Vec, + }, + BinaryOp { + op: BinaryOpKind, + lhs: Box, + rhs: Box, + }, +} + +#[derive(Debug)] +pub(crate) enum BinaryOpKind {} + +pub(crate) fn parse_operation(op: &str) -> Result> { + let tokens = Token::lexer(op.trim()) + .collect::, _>>() + .map_err(|()| eyre::eyre!("failed to lex"))?; + let stmts = parse(tokens)?; + + Ok(stmts) +} + +struct Parser { + tokens: std::iter::Peekable>, +} + +impl Parser { + fn next(&mut self) -> Result { + 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) -> Result> { + 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 { + 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 { + parse_expr_range(parser) +} + +fn parse_expr_range(parser: &mut Parser) -> Result { + 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 { + 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 { + 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), +} diff --git a/crates/intringen/Cargo.toml b/crates/intringen/Cargo.toml new file mode 100644 index 0000000..81f7bbd --- /dev/null +++ b/crates/intringen/Cargo.toml @@ -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] diff --git a/crates/intringen/src/lib.rs b/crates/intringen/src/lib.rs new file mode 100644 index 0000000..05af1f0 --- /dev/null +++ b/crates/intringen/src/lib.rs @@ -0,0 +1,3 @@ +pub mod x86; + +pub trait Lanes {} diff --git a/crates/intringen/src/x86/generated.rs b/crates/intringen/src/x86/generated.rs new file mode 100644 index 0000000..37b49c9 --- /dev/null +++ b/crates/intringen/src/x86/generated.rs @@ -0,0 +1,53 @@ +impl 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); + } +} diff --git a/crates/intringen/src/x86/mod.rs b/crates/intringen/src/x86/mod.rs new file mode 100644 index 0000000..088d44d --- /dev/null +++ b/crates/intringen/src/x86/mod.rs @@ -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 {} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..e240b9a --- /dev/null +++ b/shell.nix @@ -0,0 +1,3 @@ +{ pkgs ? import { } }: pkgs.mkShell { + packages = with pkgs; [ rustup ]; +}