Skip to content

Commit 7e96a0b

Browse files
author
sarah
committed
relax explicit lifetime requirement
1 parent 1b5aa54 commit 7e96a0b

File tree

4 files changed

+114
-71
lines changed

4 files changed

+114
-71
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ Only available with the `macro` feature.
6464

6565
Requires the first non-lifetime generic parameter, as well as the function's
6666
first input parameter to be the SIMD type.
67-
Also currently requires that all the lifetimes be explicitly specified.
6867

6968
```rust
7069
#[pulp::with_simd(sum = pulp::Arch::new())]

pulp-macro/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pulp-macro"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
edition = "2021"
55
authors = ["sarah <>"]
66
description = "Safe generic simd"

pulp-macro/src/lib.rs

Lines changed: 111 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use proc_macro2::TokenStream;
1+
use proc_macro2::{Ident, Span, TokenStream};
22
use quote::quote;
33
use syn::punctuated::Punctuated;
4-
use syn::token::{Brace, Colon};
5-
use syn::{FieldsNamed, FnArg, ItemFn};
4+
use syn::token::{Colon, PathSep};
5+
use syn::{
6+
ConstParam, FnArg, GenericParam, ItemFn, LifetimeParam, Pat, PatIdent, PatType, Path,
7+
PathSegment, Type, TypeParam, TypePath,
8+
};
69

710
#[proc_macro_attribute]
811
pub fn with_simd(
@@ -40,20 +43,13 @@ pub fn with_simd(
4043
block,
4144
} = item.clone();
4245

43-
let mut struct_generics = Punctuated::new();
44-
let mut struct_generics_lifetimes = Vec::new();
45-
let mut struct_generics_names = Vec::new();
46+
let mut struct_generics = Vec::new();
4647
let mut struct_field_names = Vec::new();
47-
let mut struct_fields = FieldsNamed {
48-
brace_token: Brace {
49-
span: sig.paren_token.span,
50-
},
51-
named: Punctuated::new(),
52-
};
48+
let mut struct_field_types = Vec::new();
5349

5450
let mut first_non_lifetime = usize::MAX;
5551
for (idx, param) in sig.generics.params.clone().into_pairs().enumerate() {
56-
let (param, comma) = param.into_tuple();
52+
let (param, _) = param.into_tuple();
5753
match &param {
5854
syn::GenericParam::Lifetime(_) => {}
5955
_ => {
@@ -63,17 +59,7 @@ pub fn with_simd(
6359
}
6460
}
6561
}
66-
match &param {
67-
syn::GenericParam::Type(ty) => struct_generics_names.push(ty.ident.clone()),
68-
syn::GenericParam::Lifetime(lt) => struct_generics_lifetimes.push(lt.lifetime.clone()),
69-
syn::GenericParam::Const(const_) => struct_generics_names.push(const_.ident.clone()),
70-
};
71-
struct_generics.push_value(param);
72-
if let Some(comma) = comma {
73-
struct_generics.push_punct(comma);
74-
}
7562
}
76-
7763
let mut new_fn_sig = sig.clone();
7864
new_fn_sig.generics.params = new_fn_sig
7965
.generics
@@ -83,49 +69,61 @@ pub fn with_simd(
8369
.filter(|(idx, _)| *idx != first_non_lifetime)
8470
.map(|(_, arg)| arg)
8571
.collect();
86-
new_fn_sig.inputs = new_fn_sig.inputs.into_iter().skip(1).collect();
72+
new_fn_sig.inputs = new_fn_sig
73+
.inputs
74+
.into_iter()
75+
.skip(1)
76+
.enumerate()
77+
.map(|(idx, arg)| {
78+
FnArg::Typed(PatType {
79+
attrs: Vec::new(),
80+
pat: Box::new(Pat::Ident(PatIdent {
81+
attrs: Vec::new(),
82+
by_ref: None,
83+
mutability: None,
84+
ident: Ident::new(&format!("__{idx}"), Span::call_site()),
85+
subpat: None,
86+
})),
87+
colon_token: Colon {
88+
spans: [Span::call_site()],
89+
},
90+
ty: match arg {
91+
FnArg::Typed(ty) => ty.ty,
92+
FnArg::Receiver(_) => panic!(),
93+
},
94+
})
95+
})
96+
.collect();
8797
new_fn_sig.ident = name.clone();
98+
let mut param_ty = Vec::new();
8899

89-
for param in sig.inputs.clone().into_pairs().skip(1) {
90-
let (param, comma) = param.into_tuple();
100+
for (idx, param) in new_fn_sig.inputs.clone().into_pairs().enumerate() {
101+
let (param, _) = param.into_tuple();
91102
let FnArg::Typed(param) = param.clone() else {
92-
return quote! {
93-
::core::compile_error!(::core::concat!(
94-
"pulp::with_simd only accepts free functions"
95-
));
96-
#item
97-
}
98-
.into();
103+
panic!();
99104
};
100-
101105
let name = *param.pat;
102106
let syn::Pat::Ident(name) = name else {
103-
return quote! {
104-
::core::compile_error!(::core::concat!(
105-
"pulp::with_simd requires function parameters to be idents"
106-
));
107-
#item
108-
}
109-
.into();
107+
panic!();
110108
};
111109

110+
let anon_ty = Ident::new(&format!("__T{idx}"), Span::call_site());
111+
112112
struct_field_names.push(name.ident.clone());
113-
let field = syn::Field {
114-
attrs: param.attrs,
115-
vis: syn::Visibility::Public(syn::token::Pub {
116-
span: proc_macro2::Span::call_site(),
117-
}),
118-
mutability: syn::FieldMutability::None,
119-
ident: Some(name.ident),
120-
colon_token: Some(Colon {
121-
spans: [proc_macro2::Span::call_site()],
122-
}),
123-
ty: *param.ty,
124-
};
125-
struct_fields.named.push_value(field);
126-
if let Some(comma) = comma {
127-
struct_fields.named.push_punct(comma);
128-
}
113+
let mut ty = Punctuated::<_, PathSep>::new();
114+
ty.push_value(PathSegment {
115+
ident: anon_ty.clone(),
116+
arguments: syn::PathArguments::None,
117+
});
118+
struct_field_types.push(Type::Path(TypePath {
119+
qself: None,
120+
path: Path {
121+
leading_colon: None,
122+
segments: ty,
123+
},
124+
}));
125+
struct_generics.push(anon_ty);
126+
param_ty.push(*param.ty);
129127
}
130128

131129
let output_ty = match sig.output.clone() {
@@ -136,33 +134,79 @@ pub fn with_simd(
136134
let fn_name = sig.ident.clone();
137135

138136
let arch = attr.value;
137+
let new_fn_generics = new_fn_sig.generics.clone();
138+
let params = new_fn_generics.params.clone();
139+
let generics = params.into_iter().collect::<Vec<_>>();
140+
let non_lt_generics_names = generics
141+
.iter()
142+
.map(|p| match p {
143+
GenericParam::Type(TypeParam { ident, .. })
144+
| GenericParam::Const(ConstParam { ident, .. }) => {
145+
quote! { #ident, }
146+
}
147+
_ => quote! {},
148+
})
149+
.collect::<Vec<_>>();
150+
let generics_decl = generics
151+
.iter()
152+
.map(|p| match p {
153+
GenericParam::Lifetime(LifetimeParam {
154+
lifetime,
155+
colon_token,
156+
bounds,
157+
..
158+
}) => {
159+
quote! { #lifetime #colon_token #bounds }
160+
}
161+
GenericParam::Type(TypeParam {
162+
ident,
163+
colon_token,
164+
bounds,
165+
..
166+
}) => {
167+
quote! { #ident #colon_token #bounds }
168+
}
169+
GenericParam::Const(ConstParam {
170+
const_token,
171+
ident,
172+
colon_token,
173+
ty,
174+
..
175+
}) => {
176+
quote! { #const_token #ident #colon_token #ty }
177+
}
178+
})
179+
.collect::<Vec<_>>();
180+
let generics_where_clause = new_fn_generics.where_clause;
139181

140-
quote! {
182+
let code = quote! {
141183
#(#attrs)*
142184
#vis #new_fn_sig {
143185
#[allow(non_camel_case_types)]
144-
struct #name<#struct_generics> #struct_fields
186+
struct #name<#(#struct_generics,)*> (#(#struct_field_types,)*);
145187

146-
impl<#struct_generics> ::pulp::WithSimd for #name<#(#struct_generics_lifetimes,)*
147-
#(#struct_generics_names,)*> { type Output = #output_ty;
188+
impl<#(#generics_decl,)*> ::pulp::WithSimd for #name<
189+
#(#param_ty,)*
190+
> #generics_where_clause {
191+
type Output = #output_ty;
148192

149193
#[inline(always)]
150-
fn with_simd<__S: ::pulp::Simd>(self, __simd: __S) -> <Self as
151-
::pulp::WithSimd>::Output { let Self { #(#struct_field_names,)* } = self;
194+
fn with_simd<__S: ::pulp::Simd>(self, __simd: __S) -> <Self as ::pulp::WithSimd>::Output {
195+
let Self ( #(#struct_field_names,)* ) = self;
152196
#[allow(unused_unsafe)]
153197
unsafe {
154198
#fn_name::<__S,
155-
#(#struct_generics_names,)*
199+
#(#non_lt_generics_names)*
156200
>(__simd, #(#struct_field_names,)*)
157201
}
158202
}
159203
}
160204

161-
(#arch).dispatch( #name::<#(#struct_generics_names,)*> { #(#struct_field_names,)* } )
205+
(#arch).dispatch( #name ( #(#struct_field_names,)* ) )
162206
}
163207

164208
#(#attrs)*
165209
#vis #sig #block
166-
}
167-
.into()
210+
};
211+
code.into()
168212
}

pulp/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pulp"
3-
version = "0.18.5"
3+
version = "0.18.6"
44
edition = "2021"
55
authors = ["sarah <>"]
66
description = "Safe generic simd"
@@ -10,7 +10,7 @@ license = "MIT"
1010
keywords = ["simd"]
1111

1212
[dependencies]
13-
pulp-macro = { version = "0.1.0", path = "../pulp-macro", optional = true }
13+
pulp-macro = { version = "0.1.1", path = "../pulp-macro", optional = true }
1414
bytemuck = "1"
1515
num-complex = { version = "0.4.4", default-features = false, features = ["bytemuck"] }
1616
libm = { version = "0.2", default-features = false }

0 commit comments

Comments
 (0)