From 647fa97f45288878afaceafd95dfaebfcecfc255 Mon Sep 17 00:00:00 2001 From: novafacing Date: Wed, 24 May 2023 00:45:26 -0700 Subject: [PATCH 1/6] Initial POC of vector indexing and enable more builtins --- c2rust-transpile/src/translator/builtins.rs | 13 ++++ c2rust-transpile/src/translator/mod.rs | 72 +++++++++++++++++---- c2rust-transpile/src/translator/simd.rs | 10 +-- 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/c2rust-transpile/src/translator/builtins.rs b/c2rust-transpile/src/translator/builtins.rs index 60275f9867..5d0a4b84ef 100644 --- a/c2rust-transpile/src/translator/builtins.rs +++ b/c2rust-transpile/src/translator/builtins.rs @@ -441,6 +441,19 @@ impl<'c> Translation<'c> { "__builtin_ia32_pcmpestris128" => self.convert_simd_builtin(ctx, "_mm_cmpestrs", args), "__builtin_ia32_pcmpestriz128" => self.convert_simd_builtin(ctx, "_mm_cmpestrz", args), + "__builtin_ia32_vcvtph2ps" => self.convert_simd_builtin(ctx, "_mm_cvtph_ps", args), + "__builtin_ia32_vcvtps2ph256" => { + self.convert_simd_builtin(ctx, "_mm256_cvtps_ph", args) + } + "__builtin_ia32_vextractf128_ps256" => { + self.convert_simd_builtin(ctx, "_mm256_extractf128_ps", args) + } + "__builtin_ia32_vextractf128_si256" => { + self.convert_simd_builtin(ctx, "_mm256_extractf128_ps", args) + } + "__builtin_ia32_roundps256" => self.convert_simd_builtin(ctx, "_mm256_round_ps", args), + "__builtin_ia32_vcvtps2ph" => self.convert_simd_builtin(ctx, "_mm_cvtps_ph", args), + "__sync_val_compare_and_swap_1" | "__sync_val_compare_and_swap_2" | "__sync_val_compare_and_swap_4" diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index d269e023f1..4cb8567200 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3598,18 +3598,33 @@ impl<'c> Translation<'c> { let lhs_node_type = lhs_node .get_type() .ok_or_else(|| format_err!("lhs node bad type"))?; - if self - .ast_context - .resolve_type(lhs_node_type) - .kind - .is_vector() - { - return Err(TranslationError::new( - self.ast_context.display_loc(src_loc), - err_msg("Attempting to index a vector type") - .context(TranslationErrorKind::OldLLVMSimd), - )); - } + // if self + // .ast_context + // .resolve_type(lhs_node_type) + // .kind + // .is_vector() + // { + // println!("Trying to index vectory type:"); + // println!("LHS node: {:?}", lhs_node); + // println!("LHS node type: {:?}", lhs_node_type); + // println!("LHS node kind: {:?}", lhs_node_kind); + // println!("LHS is indexable: {:?}", lhs_is_indexable); + // println!("LHS: {:?}", lhs); + // println!("RHS: {:?}", rhs); + // let rhs = self.convert_expr(ctx.used(), *rhs)?; + // println!("RHS converted: {:?}", rhs); + // println!("RHS node: {:?}", rhs_node); + // if let CTypeKind::Vector(vkind, size) = lhs_node_kind { + // let vector_kind = self.ast_context.resolve_type(vkind.ctype); + // println!("Vector kind: {:?} of size {}", vector_kind.kind, size); + // } + + // return Err(TranslationError::new( + // self.ast_context.display_loc(src_loc), + // err_msg("Attempting to index a vector type") + // .context(TranslationErrorKind::OldLLVMSimd), + // )); + // } let rhs = self.convert_expr(ctx.used(), *rhs)?; rhs.and_then(|rhs| { @@ -3680,6 +3695,39 @@ impl<'c> Translation<'c> { mk().index_expr(lhs, cast_int(rhs, "usize", false)) } })) + } else if lhs_node_kind.is_vector() { + // LHS is a vector type, we just need to do a transmute to an array and + // take the type + match lhs_node_kind { + CTypeKind::Vector(vkind, size) => { + // let vector_kind = self.ast_context.resolve_type(vkind.ctype); + let vector_kind_size = + self.compute_size_of_type(ctx, vkind.ctype)?; + + let vector_ty = self.convert_type(vkind.ctype)?; + + // Array size is vector_kind_size * size + let array_ty = mk().array_ty( + vector_ty, + // No need for this, we know it's packed ty x size already, we are + // just subscripting 1 ty + // mk().binary_expr( + // BinOp::Mul(Default::default()), + vector_kind_size.to_expr(), + // mk().lit_expr(mk().int_lit(*size as u128, "usize")), + // ), + ); + + let lhs = self.convert_expr(ctx.used(), *lhs)?; + Ok(lhs.map(|lhs| { + mk().unsafe_().index_expr( + transmute_expr(mk().infer_ty(), array_ty, lhs), + cast_int(rhs, "usize", false), + ) + })) + } + _ => unreachable!(), + } } else { // LHS must be ref decayed for the offset method call's self param let lhs = self.convert_expr(ctx.used().decay_ref(), *lhs)?; diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 0363b0ff66..5eb2967b53 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -11,14 +11,14 @@ use crate::c_ast::CastKind::{BitCast, IntegralCast}; /// As of rustc 1.29, rust is known to be missing some SIMD functions. /// See -static MISSING_SIMD_FUNCTIONS: [&str; 36] = [ +static MISSING_SIMD_FUNCTIONS: [&str; 35] = [ "_mm_and_si64", "_mm_andnot_si64", "_mm_cmpeq_pi16", "_mm_cmpeq_pi32", "_mm_cmpeq_pi8", "_mm_cvtm64_si64", - "_mm_cvtph_ps", + // "_mm_cvtph_ps", "_mm_cvtsi32_si64", "_mm_cvtsi64_m64", "_mm_cvtsi64_si32", @@ -249,9 +249,9 @@ impl<'c> Translation<'c> { (Float, 8) => ("_mm256_setzero_ps", 32), (Double, 2) => ("_mm_setzero_pd", 16), (Double, 4) => ("_mm256_setzero_pd", 32), - (Char, 16) | (Int, 4) | (LongLong, 2) => ("_mm_setzero_si128", 16), - (Char, 32) | (Int, 8) | (LongLong, 4) => ("_mm256_setzero_si256", 32), - (Char, 8) | (Int, 2) | (LongLong, 1) => { + (Char, 16) | (Short, 8) | (Int, 4) | (LongLong, 2) => ("_mm_setzero_si128", 16), + (Char, 32) | (Short, 16) | (Int, 8) | (LongLong, 4) => ("_mm256_setzero_si256", 32), + (Char, 8) | (Short, 4) | (Int, 2) | (LongLong, 1) => { // __m64 is still unstable as of rust 1.29 self.use_feature("stdsimd"); From aaff054478b6674029b271455bea194153cf359b Mon Sep 17 00:00:00 2001 From: novafacing Date: Wed, 24 May 2023 21:31:23 -0700 Subject: [PATCH 2/6] Implement use item renaming --- c2rust-ast-builder/src/builder.rs | 47 ++++++++++++++ c2rust-transpile/src/rust_ast/item_store.rs | 50 ++++++++++++++- c2rust-transpile/src/translator/builtins.rs | 2 + c2rust-transpile/src/translator/mod.rs | 66 ++++++-------------- c2rust-transpile/src/translator/simd.rs | 69 +++++++++++++++++++-- 5 files changed, 180 insertions(+), 54 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 252339c988..873e2f9065 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -1766,6 +1766,53 @@ impl Builder { })) } + pub fn use_multiple_item_rename( + self, + path: Pa, + inner: It, + rename: RIt, + ) -> Box + where + Pa: Make, + I: Make, + It: Iterator, + RIt: Iterator>, + { + let path = path.make(&self); + let inner_trees = inner + .zip(rename) + .map(|(i, r)| { + if let Some(rename) = r { + UseTree::Rename(UseRename { + ident: i.make(&self), + as_token: Token![as](self.span), + rename: rename.make(&self), + }) + } else { + UseTree::Name(UseName { + ident: i.make(&self), + }) + } + }) + .collect(); + let leading_colon = path.leading_colon; + let tree = use_tree_with_prefix( + path, + UseTree::Group(UseGroup { + brace_token: token::Brace(self.span), + items: inner_trees, + }), + ); + Box::new(Item::Use(ItemUse { + attrs: self.attrs, + vis: self.vis, + use_token: Token![use](self.span), + leading_colon, + semi_token: Token![;](self.span), + tree, + })) + } + pub fn use_glob_item(self, path: Pa) -> Box where Pa: Make, diff --git a/c2rust-transpile/src/rust_ast/item_store.rs b/c2rust-transpile/src/rust_ast/item_store.rs index c6a5399467..57e387422b 100644 --- a/c2rust-transpile/src/rust_ast/item_store.rs +++ b/c2rust-transpile/src/rust_ast/item_store.rs @@ -9,6 +9,7 @@ use std::mem::swap; pub struct MultiImport { attrs: Option, leaves: IndexSet, + renames: IndexMap, } impl MultiImport { @@ -16,6 +17,7 @@ impl MultiImport { MultiImport { attrs: None, leaves: IndexSet::new(), + renames: IndexMap::new(), } } @@ -33,6 +35,28 @@ impl MultiImport { self.insert(leaf); self.attrs = Some(attrs); } + + pub fn insert_with_rename<'a, S>(&mut self, leaf: S, rename: S) + where + S: Into>, + { + let leaf: Cow<'a, str> = leaf.into(); + self.leaves.insert(leaf.clone().into_owned()); + self.renames + .insert(leaf.into_owned(), rename.into().into_owned()); + } + + pub fn insert_with_attr_rename<'a, S>(&mut self, leaf: S, attrs: Builder, rename: S) + where + S: Into>, + { + self.insert_with_rename(leaf, rename); + self.attrs = Some(attrs); + } + + pub fn insert_attrs(&mut self, attrs: Builder) { + self.attrs = Some(attrs); + } } #[derive(Debug, Default)] @@ -55,9 +79,15 @@ impl PathedMultiImports { if leaves.len() == 1 { path.push(leaves.pop().unwrap()); - attrs.use_simple_item(path, None as Option) + let rename = path.last().and_then(|l| imports.renames.get(l).cloned()); + + attrs.use_simple_item(path, rename) } else { - attrs.use_multiple_item(path, leaves.into_iter()) + attrs.use_multiple_item_rename( + path, + leaves.clone().into_iter(), + leaves.iter().map(|l| imports.renames.get(l).cloned()), + ) } } @@ -95,6 +125,22 @@ impl ItemStore { self.uses.get_mut(path).insert_with_attr(ident, attrs) } + pub fn add_use_with_rename(&mut self, path: Vec, ident: &str, rename: &str) { + self.uses.get_mut(path).insert_with_rename(ident, rename) + } + + pub fn add_use_with_attr_rename( + &mut self, + path: Vec, + ident: &str, + attrs: Builder, + rename: &str, + ) { + self.uses + .get_mut(path) + .insert_with_attr_rename(ident, attrs, rename) + } + pub fn drain(&mut self) -> (Vec>, Vec, PathedMultiImports) { let mut items = Vec::new(); let mut foreign_items = Vec::new(); diff --git a/c2rust-transpile/src/translator/builtins.rs b/c2rust-transpile/src/translator/builtins.rs index 5d0a4b84ef..f3ad8b2524 100644 --- a/c2rust-transpile/src/translator/builtins.rs +++ b/c2rust-transpile/src/translator/builtins.rs @@ -44,6 +44,8 @@ impl<'c> Translation<'c> { } }; + println!("translating builtin_name: {}", builtin_name); + match builtin_name { "__builtin_huge_valf" => Ok(WithStmts::new_val( mk().abs_path_expr(vec!["core", "f32", "INFINITY"]), diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 4cb8567200..b971bd271f 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3595,37 +3595,6 @@ impl<'c> Translation<'c> { (rhs, lhs, rhs_node) }; - let lhs_node_type = lhs_node - .get_type() - .ok_or_else(|| format_err!("lhs node bad type"))?; - // if self - // .ast_context - // .resolve_type(lhs_node_type) - // .kind - // .is_vector() - // { - // println!("Trying to index vectory type:"); - // println!("LHS node: {:?}", lhs_node); - // println!("LHS node type: {:?}", lhs_node_type); - // println!("LHS node kind: {:?}", lhs_node_kind); - // println!("LHS is indexable: {:?}", lhs_is_indexable); - // println!("LHS: {:?}", lhs); - // println!("RHS: {:?}", rhs); - // let rhs = self.convert_expr(ctx.used(), *rhs)?; - // println!("RHS converted: {:?}", rhs); - // println!("RHS node: {:?}", rhs_node); - // if let CTypeKind::Vector(vkind, size) = lhs_node_kind { - // let vector_kind = self.ast_context.resolve_type(vkind.ctype); - // println!("Vector kind: {:?} of size {}", vector_kind.kind, size); - // } - - // return Err(TranslationError::new( - // self.ast_context.display_loc(src_loc), - // err_msg("Attempting to index a vector type") - // .context(TranslationErrorKind::OldLLVMSimd), - // )); - // } - let rhs = self.convert_expr(ctx.used(), *rhs)?; rhs.and_then(|rhs| { let simple_index_array = if ctx.needs_address() { @@ -3699,27 +3668,28 @@ impl<'c> Translation<'c> { // LHS is a vector type, we just need to do a transmute to an array and // take the type match lhs_node_kind { - CTypeKind::Vector(vkind, size) => { - // let vector_kind = self.ast_context.resolve_type(vkind.ctype); - let vector_kind_size = + CTypeKind::Vector(vkind, _vsize) => { + let vector_kind_size_of = self.compute_size_of_type(ctx, vkind.ctype)?; - let vector_ty = self.convert_type(vkind.ctype)?; - // Array size is vector_kind_size * size - let array_ty = mk().array_ty( - vector_ty, - // No need for this, we know it's packed ty x size already, we are - // just subscripting 1 ty - // mk().binary_expr( - // BinOp::Mul(Default::default()), - vector_kind_size.to_expr(), - // mk().lit_expr(mk().int_lit(*size as u128, "usize")), - // ), - ); - let lhs = self.convert_expr(ctx.used(), *lhs)?; + let lhs_type = lhs_node + .get_type() + .ok_or_else(|| format_err!("bad lhs type"))?; + let lhs_type_size_of = self.compute_size_of_type(ctx, lhs_type)?; + Ok(lhs.map(|lhs| { + // Array size is vector_kind_size (e.g. size_of::<__mm256>()) / element size (e.g. size_of::()) + let array_ty = mk().array_ty( + vector_ty, + mk().binary_expr( + BinOp::Div(Default::default()), + // mk().lit_expr(mk().int_lit(*size as u128, "usize")), + lhs_type_size_of.to_expr(), + vector_kind_size_of.to_expr(), + ), + ); mk().unsafe_().index_expr( transmute_expr(mk().infer_ty(), array_ty, lhs), cast_int(rhs, "usize", false), @@ -3768,6 +3738,7 @@ impl<'c> Translation<'c> { })?, ) .map(|ty| &self.ast_context.resolve_type(ty.ctype).kind); + let is_variadic = match fn_ty { Some(CTypeKind::Function(_, _, is_variadic, _, _)) => *is_variadic, _ => false, @@ -3787,6 +3758,7 @@ impl<'c> Translation<'c> { return self.convert_builtin(ctx, fexp, args); } + // Function pointer call _ => { let callee = self.convert_expr(ctx.used(), func)?; diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 5eb2967b53..78f3ff2ca9 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -11,20 +11,18 @@ use crate::c_ast::CastKind::{BitCast, IntegralCast}; /// As of rustc 1.29, rust is known to be missing some SIMD functions. /// See -static MISSING_SIMD_FUNCTIONS: [&str; 35] = [ +static MISSING_SIMD_FUNCTIONS: &[&str] = &[ "_mm_and_si64", "_mm_andnot_si64", "_mm_cmpeq_pi16", "_mm_cmpeq_pi32", "_mm_cmpeq_pi8", "_mm_cvtm64_si64", - // "_mm_cvtph_ps", "_mm_cvtsi32_si64", "_mm_cvtsi64_m64", "_mm_cvtsi64_si32", "_mm_empty", "_mm_free", - "_mm_loadu_si64", "_mm_madd_pi16", "_mm_malloc", "_mm_mulhi_pi16", @@ -51,20 +49,54 @@ static MISSING_SIMD_FUNCTIONS: [&str; 35] = [ ]; static SIMD_X86_64_ONLY: &[&str] = &[ + "_mm_crc32_u64", + "_mm_cvti64_sd", + "_mm_cvti64_ss", + "_mm_cvt_roundi64_sd", + "_mm_cvt_roundi64_ss", + "_mm_cvt_roundsd_i64", + "_mm_cvt_roundsd_si64", + "_mm_cvt_roundsd_u64", + "_mm_cvt_roundsi64_sd", + "_mm_cvt_roundsi64_ss", + "_mm_cvt_roundss_i64", + "_mm_cvt_roundss_si64", + "_mm_cvt_roundss_u64", + "_mm_cvt_roundu64_sd", + "_mm_cvt_roundu64_ss", + "_mm_cvtsd_i64", "_mm_cvtsd_si64", + "_mm_cvtsd_si64x", + "_mm_cvtsd_u64", "_mm_cvtsi128_si64", "_mm_cvtsi128_si64x", "_mm_cvtsi64_sd", "_mm_cvtsi64_si128", "_mm_cvtsi64_ss", + "_mm_cvtsi64x_sd", + "_mm_cvtsi64x_si128", + "_mm_cvtss_i64", "_mm_cvtss_si64", + "_mm_cvtss_u64", + "_mm_cvtt_roundsd_i64", + "_mm_cvtt_roundsd_si64", + "_mm_cvtt_roundsd_u64", + "_mm_cvtt_roundss_i64", + "_mm_cvtt_roundss_si64", + "_mm_cvtt_roundss_u64", + "_mm_cvttsd_i64", "_mm_cvttsd_si64", "_mm_cvttsd_si64x", + "_mm_cvttsd_u64", + "_mm_cvttss_i64", "_mm_cvttss_si64", - "_mm_stream_si64", + "_mm_cvttss_u64", + "_mm_cvtu64_sd", + "_mm_cvtu64_ss", "_mm_extract_epi64", "_mm_insert_epi64", - "_mm_crc32_u64", + "_mm_stream_si64", + "_mm_tzcnt_64", ]; fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) { @@ -84,6 +116,24 @@ fn add_arch_use(store: &mut ItemStore, arch_name: &str, item_name: &str) { ); } +fn add_arch_use_rename(store: &mut ItemStore, arch_name: &str, item_name: &str, rename: &str) { + store.add_use_with_attr_rename( + vec!["core".into(), "arch".into(), arch_name.into()], + item_name, + mk().meta_item_attr( + AttrStyle::Outer, + mk().meta_list( + "cfg", + vec![NestedMeta::Meta( + mk().meta_namevalue("target_arch", arch_name), + )], + ), + ) + .pub_(), + rename, + ); +} + impl<'c> Translation<'c> { /// Given the name of a typedef check if its one of the SIMD types. /// This function returns `true` when the name of the type is one that @@ -107,6 +157,15 @@ impl<'c> Translation<'c> { true } + "__m128_u" | "__m128i_u" | "__m128d_u" | "__m256_u" | "__m256i_u" | "__m256d_u" => { + // FOr these, we need to `use core::arch::x86::x as __m128i_u` and so on + self.with_cur_file_item_store(|item_store| { + add_arch_use_rename(item_store, "x86", name, &name.replace("_u", "")); + add_arch_use_rename(item_store, "x86_64", name, &name.replace("_u", "")); + }); + + true + } // These seem to be C internal types only, and shouldn't need any explicit support. // See https://internals.rust-lang.org/t/getting-explicit-simd-on-stable-rust/4380/115 "__v1di" From 528b9413e047c6cfa508b3de2e007b2f5edbbfb3 Mon Sep 17 00:00:00 2001 From: novafacing Date: Sat, 27 May 2023 10:26:20 -0700 Subject: [PATCH 3/6] Fix and test implementation of use renaming --- c2rust-ast-builder/src/builder.rs | 33 +++++++++++---------- c2rust-transpile/src/rust_ast/item_store.rs | 5 ++-- c2rust-transpile/src/translator/builtins.rs | 2 -- c2rust-transpile/src/translator/mod.rs | 1 + c2rust-transpile/src/translator/simd.rs | 13 ++++++-- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 873e2f9065..597f0f3989 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -1713,6 +1713,7 @@ impl Builder { let (prefix, ident) = split_path(path); let ident = ident.expect("use_simple_item called with path `::`"); let tree = if let Some(rename) = rename { + println!("use_smple_item: ident: {:?}, rename: {:?}", ident, rename); use_tree_with_prefix( prefix, UseTree::Rename(UseRename { @@ -1766,7 +1767,7 @@ impl Builder { })) } - pub fn use_multiple_item_rename( + pub fn use_multiple_item_rename( self, path: Pa, inner: It, @@ -1775,25 +1776,27 @@ impl Builder { where Pa: Make, I: Make, + Ip: Into<(I, I)>, It: Iterator, - RIt: Iterator>, + RIt: Iterator, { let path = path.make(&self); let inner_trees = inner - .zip(rename) - .map(|(i, r)| { - if let Some(rename) = r { - UseTree::Rename(UseRename { - ident: i.make(&self), - as_token: Token![as](self.span), - rename: rename.make(&self), - }) - } else { - UseTree::Name(UseName { - ident: i.make(&self), - }) - } + .map(|i| { + UseTree::Name(UseName { + ident: i.make(&self), + }) }) + .chain(rename.map(|ip| { + let (ident, rename) = ip.into(); + let ident = ident.make(&self); + let rename = rename.make(&self); + UseTree::Rename(UseRename { + ident, + as_token: Token![as](self.span), + rename, + }) + })) .collect(); let leading_colon = path.leading_colon; let tree = use_tree_with_prefix( diff --git a/c2rust-transpile/src/rust_ast/item_store.rs b/c2rust-transpile/src/rust_ast/item_store.rs index 57e387422b..21fce96ffc 100644 --- a/c2rust-transpile/src/rust_ast/item_store.rs +++ b/c2rust-transpile/src/rust_ast/item_store.rs @@ -41,7 +41,6 @@ impl MultiImport { S: Into>, { let leaf: Cow<'a, str> = leaf.into(); - self.leaves.insert(leaf.clone().into_owned()); self.renames .insert(leaf.into_owned(), rename.into().into_owned()); } @@ -85,8 +84,8 @@ impl PathedMultiImports { } else { attrs.use_multiple_item_rename( path, - leaves.clone().into_iter(), - leaves.iter().map(|l| imports.renames.get(l).cloned()), + leaves.into_iter(), + imports.renames.into_iter(), ) } } diff --git a/c2rust-transpile/src/translator/builtins.rs b/c2rust-transpile/src/translator/builtins.rs index f3ad8b2524..5d0a4b84ef 100644 --- a/c2rust-transpile/src/translator/builtins.rs +++ b/c2rust-transpile/src/translator/builtins.rs @@ -44,8 +44,6 @@ impl<'c> Translation<'c> { } }; - println!("translating builtin_name: {}", builtin_name); - match builtin_name { "__builtin_huge_valf" => Ok(WithStmts::new_val( mk().abs_path_expr(vec!["core", "f32", "INFINITY"]), diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index b971bd271f..f3d268259d 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -797,6 +797,7 @@ pub fn translate( if tcfg.reorganize_definitions { t.use_feature("register_tool"); } + println!("Making submodule for {:?}", file_id); let mut submodule = make_submodule( &t.ast_context, mod_item_store, diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 78f3ff2ca9..5478510aac 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -158,10 +158,17 @@ impl<'c> Translation<'c> { true } "__m128_u" | "__m128i_u" | "__m128d_u" | "__m256_u" | "__m256i_u" | "__m256d_u" => { - // FOr these, we need to `use core::arch::x86::x as __m128i_u` and so on + // Rust doesn't have unaligned SIMD types, but it's not incorrect to use an unaligned + // type instead, it's just slightly less efficient. We'll just use the aligned type + // and rename it to the unaligned type. self.with_cur_file_item_store(|item_store| { - add_arch_use_rename(item_store, "x86", name, &name.replace("_u", "")); - add_arch_use_rename(item_store, "x86_64", name, &name.replace("_u", "")); + add_arch_use_rename(item_store, "x86", &name.replace("_u", ""), name); + add_arch_use_rename(item_store, "x86_64", &name.replace("_u", ""), name); + }); + + self.with_cur_file_item_store(|item_store| { + add_arch_use(item_store, "x86", &name.replace("_u", "")); + add_arch_use(item_store, "x86_64", &name.replace("_u", "")); }); true From 6493fd9870c3ee61c62578ce1ebfa112d5f97474 Mon Sep 17 00:00:00 2001 From: novafacing Date: Sat, 27 May 2023 12:21:42 -0700 Subject: [PATCH 4/6] Add gcc internal vector type emission and repr_simd feature emit --- c2rust-ast-builder/src/builder.rs | 10 ++++ c2rust-transpile/src/rust_ast/item_store.rs | 2 +- c2rust-transpile/src/translator/simd.rs | 57 ++++++++++++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 597f0f3989..9bf99666ae 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -1966,6 +1966,16 @@ impl Builder { } } + pub fn struct_field_anon(self, ty: Box) -> Field { + Field { + ident: None, + vis: self.vis, + attrs: self.attrs, + ty: *ty, + colon_token: None, + } + } + pub fn enum_field(self, ty: Box) -> Field { Field { ident: None, diff --git a/c2rust-transpile/src/rust_ast/item_store.rs b/c2rust-transpile/src/rust_ast/item_store.rs index 21fce96ffc..a16fc0a102 100644 --- a/c2rust-transpile/src/rust_ast/item_store.rs +++ b/c2rust-transpile/src/rust_ast/item_store.rs @@ -1,6 +1,6 @@ use c2rust_ast_builder::{mk, Builder}; use indexmap::{IndexMap, IndexSet}; -use syn::{ForeignItem, Ident, Item}; +use syn::{ForeignItem, Item}; use std::borrow::Cow; use std::mem::swap; diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 5478510aac..ecda7c6073 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -208,11 +208,66 @@ impl<'c> Translation<'c> { | "__v8su" | "__v16hu" | "__mm_loadh_pi_v2f32" - | "__mm_loadl_pi_v2f32" => true, + | "__mm_loadl_pi_v2f32" => self.generate_simd_type(name)?, _ => false, }) } + /// Given the name of a SIMD typedef that is valid but not a built in core Rust type, attempt + /// to generate a Rust type for it. + /// https://internals.rust-lang.org/t/getting-explicit-simd-on-stable-rust/4380?page=6 + pub fn generate_simd_type(&self, name: &str) -> TranslationResult { + let prefix = name + .chars() + .take_while(|c| !c.is_numeric()) + .collect::(); + let width = name + .split_at(prefix.len()) + .1 + .chars() + .take_while(|c| c.is_numeric()) + .collect::() + .parse::() + .unwrap(); + let elem_ty = name.split_at(prefix.len() + width.to_string().len()).1; + // Prefixes: q (8), h (16), s (32), d (64) + // Signedness: i (signed), u (unsigned), f (float) + let rust_elem_ty = match elem_ty { + "qi" => "i8", // ex: v8qi => vector 8 signed 8-bit ints + "hi" => "i16", // ex: v4hi => vector 4 signed 16-bit ints + "si" => "i32", // ex: v2si => vector 2 signed (standard? What does the "s" stand for?) 32-bit ints + "di" => "i64", // ex: v1di => vector 1 signed 64-bit ints + "qu" => "u8", // ex: v8qu => vector 8 unsigned 8-bit ints + "hu" => "u16", // ex: v4hu => vector 4 unsigned 16-bit ints + "su" => "u32", // ex: v2su => vector 2 unsigned (standard? What does the "s" stand for?) 32-bit ints + "du" => "u64", // ex: v1du => vector 1 unsigned 64-bit ints + "sf" => "f32", // ex: v4sf => vector 4 signed 32-bit floats + "df" => "f64", // ex: v2df => vector 2 signed 64-bit floats + _ => return Err(format_err!("Unknown SIMD type: {}", name).into()), + }; + + self.with_cur_file_item_store(|item_store| { + // Generate type like: + // #[repr(simd)] + // #[derive(Copy, Clone, Debug)] + // pub struct __v8hi(pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16); + self.use_feature("repr_simd"); + + let struct_fields = (0..width) + .map(|_| mk().pub_().ident_ty(rust_elem_ty)) + .map(|ty| mk().struct_field_anon(ty)) + .collect(); + let struct_decl = + mk().pub_() + .call_attr("repr", vec!["simd"]) + .struct_item(name, struct_fields, true); + + item_store.add_item(struct_decl); + }); + + Ok(true) + } + /// Determine if a particular function name is an SIMD primitive. If so an appropriate /// use statement is generated, `true` is returned, and no further processing will need to be done. pub fn import_simd_function(&self, name: &str) -> TranslationResult { From 9751944ffca0de713735d1931cf8796c3233e1f2 Mon Sep 17 00:00:00 2001 From: novafacing Date: Sat, 27 May 2023 13:19:39 -0700 Subject: [PATCH 5/6] Implement simd type generation but need to change to 'use as' aliasing because of _cvtss_sh type functions --- c2rust-transpile/src/translator/simd.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index ecda7c6073..7051763964 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -306,7 +306,7 @@ impl<'c> Translation<'c> { match self.ast_context[expr_id].kind { // For some reason there seems to be an incorrect implicit cast here to char // it's possible the builtin takes a char even though the function takes an int - ImplicitCast(_, expr_id, IntegralCast, _, _) => expr_id, + ImplicitCast(_, _, IntegralCast, _, _) => expr_id, // (internal)(external)(vector input) ExplicitCast(qty, _, BitCast, _, _) => { if let CTypeKind::Vector(..) = self.ast_context.resolve_type(qty.ctype).kind { @@ -345,6 +345,7 @@ impl<'c> Translation<'c> { let call = mk().call_expr(mk().ident_expr(fn_name), call_params); if ctx.is_used() { + // Get the ty of the return value of the call Ok(WithStmts::new_val(call)) } else { Ok(WithStmts::new( From 9bb7c77e81f566248e6fc3941fd711bc061695cf Mon Sep 17 00:00:00 2001 From: novafacing Date: Sat, 27 May 2023 16:30:31 -0700 Subject: [PATCH 6/6] Cleaned up use renaming --- c2rust-ast-builder/src/builder.rs | 84 ++++++++++++++++++--- c2rust-transpile/src/rust_ast/item_store.rs | 32 ++++++-- c2rust-transpile/src/translator/mod.rs | 1 - c2rust-transpile/src/translator/simd.rs | 45 +++++------ 4 files changed, 114 insertions(+), 48 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 9bf99666ae..40131c384b 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -1,6 +1,9 @@ //! Helpers for building AST nodes. Normally used by calling `mk().some_node(args...)`. -use std::str; +use std::{ + iter::{once, repeat}, + str, +}; use proc_macro2::{Span, TokenStream, TokenTree}; use std::default::Default; @@ -1693,6 +1696,62 @@ impl Builder { })) } + // `use ;` item + pub fn use_simple_item_rename(self, path: Pa, rename: Option) -> Box + where + Pa: Make, + I: Make, + Ip: Into<(I, RIt)>, + RIt: Iterator, + { + let path = path.make(&self); + + fn split_path(mut p: Path) -> (Path, Option) { + if let Some(punct) = p.segments.pop() { + (p, Some(punct.into_value().ident)) + } else { + (p, None) + } + } + let leading_colon = path.leading_colon; + let (prefix, ident) = split_path(path); + let ident = ident.expect("use_simple_item called with path `::`"); + + let inner_trees = if let Some(rename) = rename { + let (rename_ident, renames) = rename.into(); + let rename_ident = rename_ident.make(&self); + + once(UseTree::Name(UseName { ident })) + .chain(repeat(rename_ident).zip(renames).map(|(ident, rename)| { + UseTree::Rename(UseRename { + ident, + as_token: Token![as](self.span), + rename: rename.make(&self), + }) + })) + .collect() + } else { + once(UseTree::Name(UseName { ident })).collect() + }; + + let tree = use_tree_with_prefix( + prefix, + UseTree::Group(UseGroup { + brace_token: token::Brace(self.span), + items: inner_trees, + }), + ); + + Box::new(Item::Use(ItemUse { + attrs: self.attrs, + vis: self.vis, + use_token: Token![use](self.span), + leading_colon, + semi_token: Token![;](self.span), + tree, + })) + } + // `use ;` item pub fn use_simple_item(self, path: Pa, rename: Option) -> Box where @@ -1700,7 +1759,6 @@ impl Builder { I: Make, { let path = path.make(&self); - let rename = rename.map(|n| n.make(&self)); fn split_path(mut p: Path) -> (Path, Option) { if let Some(punct) = p.segments.pop() { @@ -1712,19 +1770,20 @@ impl Builder { let leading_colon = path.leading_colon; let (prefix, ident) = split_path(path); let ident = ident.expect("use_simple_item called with path `::`"); + let tree = if let Some(rename) = rename { - println!("use_smple_item: ident: {:?}, rename: {:?}", ident, rename); use_tree_with_prefix( prefix, UseTree::Rename(UseRename { ident, as_token: Token![as](self.span), - rename, + rename: rename.make(&self), }), ) } else { use_tree_with_prefix(prefix, UseTree::Name(UseName { ident })) }; + Box::new(Item::Use(ItemUse { attrs: self.attrs, vis: self.vis, @@ -1776,7 +1835,7 @@ impl Builder { where Pa: Make, I: Make, - Ip: Into<(I, I)>, + Ip: Into<(I, It)>, It: Iterator, RIt: Iterator, { @@ -1787,14 +1846,15 @@ impl Builder { ident: i.make(&self), }) }) - .chain(rename.map(|ip| { - let (ident, rename) = ip.into(); + .chain(rename.flat_map(|ip| { + let (ident, renames) = ip.into(); let ident = ident.make(&self); - let rename = rename.make(&self); - UseTree::Rename(UseRename { - ident, - as_token: Token![as](self.span), - rename, + repeat(ident).zip(renames).map(|(ident, rename)| { + UseTree::Rename(UseRename { + ident: ident.make(&self), + as_token: Token![as](self.span), + rename: rename.make(&self), + }) }) })) .collect(); diff --git a/c2rust-transpile/src/rust_ast/item_store.rs b/c2rust-transpile/src/rust_ast/item_store.rs index a16fc0a102..1a12b01cc8 100644 --- a/c2rust-transpile/src/rust_ast/item_store.rs +++ b/c2rust-transpile/src/rust_ast/item_store.rs @@ -9,7 +9,7 @@ use std::mem::swap; pub struct MultiImport { attrs: Option, leaves: IndexSet, - renames: IndexMap, + renames: IndexMap>, } impl MultiImport { @@ -40,9 +40,17 @@ impl MultiImport { where S: Into>, { - let leaf: Cow<'a, str> = leaf.into(); - self.renames - .insert(leaf.into_owned(), rename.into().into_owned()); + let leaf: String = leaf.into().into_owned(); + let rename: String = rename.into().into_owned(); + if let Some(renames) = self.renames.get_mut(&leaf) { + renames.insert(rename); + } else { + let mut set = IndexSet::new(); + set.insert(rename); + self.renames.insert(leaf.clone(), set); + }; + + self.insert(leaf); } pub fn insert_with_attr_rename<'a, S>(&mut self, leaf: S, attrs: Builder, rename: S) @@ -76,16 +84,24 @@ impl PathedMultiImports { let attrs = imports.attrs.unwrap_or_else(mk); if leaves.len() == 1 { - path.push(leaves.pop().unwrap()); + let leaf = leaves.pop().unwrap(); + path.push(leaf.clone()); - let rename = path.last().and_then(|l| imports.renames.get(l).cloned()); + let renames = imports + .renames + .get(&leaf) + .map(|r| Some((leaf.clone(), r.clone().into_iter()))) + .unwrap_or(None); - attrs.use_simple_item(path, rename) + attrs.use_simple_item_rename(path, renames) } else { attrs.use_multiple_item_rename( path, leaves.into_iter(), - imports.renames.into_iter(), + imports + .renames + .iter() + .map(|(leaf, renames)| (leaf.clone(), renames.clone().into_iter())), ) } } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index f3d268259d..b971bd271f 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -797,7 +797,6 @@ pub fn translate( if tcfg.reorganize_definitions { t.use_feature("register_tool"); } - println!("Making submodule for {:?}", file_id); let mut submodule = make_submodule( &t.ast_context, mod_item_store, diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index 7051763964..a49dfe6fc5 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -232,37 +232,28 @@ impl<'c> Translation<'c> { let elem_ty = name.split_at(prefix.len() + width.to_string().len()).1; // Prefixes: q (8), h (16), s (32), d (64) // Signedness: i (signed), u (unsigned), f (float) - let rust_elem_ty = match elem_ty { - "qi" => "i8", // ex: v8qi => vector 8 signed 8-bit ints - "hi" => "i16", // ex: v4hi => vector 4 signed 16-bit ints - "si" => "i32", // ex: v2si => vector 2 signed (standard? What does the "s" stand for?) 32-bit ints - "di" => "i64", // ex: v1di => vector 1 signed 64-bit ints - "qu" => "u8", // ex: v8qu => vector 8 unsigned 8-bit ints - "hu" => "u16", // ex: v4hu => vector 4 unsigned 16-bit ints - "su" => "u32", // ex: v2su => vector 2 unsigned (standard? What does the "s" stand for?) 32-bit ints - "du" => "u64", // ex: v1du => vector 1 unsigned 64-bit ints - "sf" => "f32", // ex: v4sf => vector 4 signed 32-bit floats - "df" => "f64", // ex: v2df => vector 2 signed 64-bit floats + let elem_width = match elem_ty { + "qi" | "qu" => 8, + "hi" | "hu" => 16, + "si" | "su" | "sf" => 32, + "di" | "du" | "df" => 64, _ => return Err(format_err!("Unknown SIMD type: {}", name).into()), }; + // Suffix is either 'd' (for 64-bit fp), 'i' (for integral types) or '' (for 32-bit fp) + let suffix = match elem_ty { + "df" => "d", + "sf" => "", + _ => "i", + }; + + let conversion_ty_name = format!("__m{}{}", width * elem_width, suffix,); + self.with_cur_file_item_store(|item_store| { - // Generate type like: - // #[repr(simd)] - // #[derive(Copy, Clone, Debug)] - // pub struct __v8hi(pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16); - self.use_feature("repr_simd"); - - let struct_fields = (0..width) - .map(|_| mk().pub_().ident_ty(rust_elem_ty)) - .map(|ty| mk().struct_field_anon(ty)) - .collect(); - let struct_decl = - mk().pub_() - .call_attr("repr", vec!["simd"]) - .struct_item(name, struct_fields, true); - - item_store.add_item(struct_decl); + add_arch_use_rename(item_store, "x86", &conversion_ty_name, name); + add_arch_use_rename(item_store, "x86_64", &conversion_ty_name, name); + add_arch_use(item_store, "x86", &conversion_ty_name); + add_arch_use(item_store, "x86_64", &conversion_ty_name); }); Ok(true)