mirror of
https://github.com/vosen/ZLUDA.git
synced 2025-04-20 00:14:45 +00:00
Add types for call instruction
This commit is contained in:
parent
22492ec7f1
commit
34b0a67f0a
2 changed files with 207 additions and 31 deletions
|
@ -1,8 +1,8 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{
|
||||
braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, PathSegment, Token, Type,
|
||||
TypeParam, Visibility,
|
||||
braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, LitBool, PathSegment, Token,
|
||||
Type, TypeParam, Visibility,
|
||||
};
|
||||
|
||||
pub mod parser;
|
||||
|
@ -168,7 +168,10 @@ pub struct InstructionVariant {
|
|||
pub type_: Option<Option<Expr>>,
|
||||
pub space: Option<Expr>,
|
||||
pub data: Option<Type>,
|
||||
pub arguments: Option<InstructionArguments>,
|
||||
pub arguments: Option<Arguments>,
|
||||
pub visit: Option<Expr>,
|
||||
pub visit_mut: Option<Expr>,
|
||||
pub map: Option<Expr>,
|
||||
}
|
||||
|
||||
impl InstructionVariant {
|
||||
|
@ -194,17 +197,23 @@ impl InstructionVariant {
|
|||
}
|
||||
Some(args) => {
|
||||
let args_name = self.args_name();
|
||||
match &args.generic {
|
||||
None => {
|
||||
match &args {
|
||||
Arguments::Def(InstructionArguments { generic: None, .. }) => {
|
||||
quote! {
|
||||
arguments: #args_name,
|
||||
}
|
||||
}
|
||||
Some(generics) => {
|
||||
Arguments::Def(InstructionArguments {
|
||||
generic: Some(generics),
|
||||
..
|
||||
}) => {
|
||||
quote! {
|
||||
arguments: #args_name <#generics>,
|
||||
}
|
||||
}
|
||||
Arguments::Decl(type_) => quote! {
|
||||
arguments: #type_,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -214,15 +223,21 @@ impl InstructionVariant {
|
|||
}
|
||||
|
||||
fn emit_visit(&self, enum_: &Ident, tokens: &mut TokenStream) {
|
||||
self.emit_visit_impl(enum_, tokens, InstructionArguments::emit_visit)
|
||||
self.emit_visit_impl(&self.visit, enum_, tokens, InstructionArguments::emit_visit)
|
||||
}
|
||||
|
||||
fn emit_visit_mut(&self, enum_: &Ident, tokens: &mut TokenStream) {
|
||||
self.emit_visit_impl(enum_, tokens, InstructionArguments::emit_visit_mut)
|
||||
self.emit_visit_impl(
|
||||
&self.visit_mut,
|
||||
enum_,
|
||||
tokens,
|
||||
InstructionArguments::emit_visit_mut,
|
||||
)
|
||||
}
|
||||
|
||||
fn emit_visit_impl(
|
||||
&self,
|
||||
visit_fn: &Option<Expr>,
|
||||
enum_: &Ident,
|
||||
tokens: &mut TokenStream,
|
||||
mut fn_: impl FnMut(&InstructionArguments, &Option<Option<Expr>>, &Option<Expr>) -> TokenStream,
|
||||
|
@ -236,7 +251,14 @@ impl InstructionVariant {
|
|||
.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
Some(args) => args,
|
||||
Some(Arguments::Decl(_)) => {
|
||||
quote! {
|
||||
#enum_ :: #name { data, arguments } => { #visit_fn }
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
Some(Arguments::Def(args)) => args,
|
||||
};
|
||||
let data = &self.data.as_ref().map(|_| quote! { data,});
|
||||
let arg_calls = fn_(arguments, &self.type_, &self.space);
|
||||
|
@ -250,10 +272,24 @@ impl InstructionVariant {
|
|||
|
||||
fn emit_visit_map(&self, enum_: &Ident, tokens: &mut TokenStream) {
|
||||
let name = &self.name;
|
||||
let arguments = &self.arguments.as_ref().map(|_| quote! { arguments,});
|
||||
let data = &self.data.as_ref().map(|_| quote! { data,});
|
||||
let arguments = match self.arguments {
|
||||
None => None,
|
||||
Some(Arguments::Decl(_)) => {
|
||||
let map = self.map.as_ref().unwrap();
|
||||
quote! {
|
||||
#enum_ :: #name { #data arguments } => {
|
||||
#map
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
return;
|
||||
}
|
||||
Some(Arguments::Def(ref def)) => Some(def),
|
||||
};
|
||||
let arguments_ident = &self.arguments.as_ref().map(|_| quote! { arguments,});
|
||||
let mut arg_calls = None;
|
||||
let arguments_init = self.arguments.as_ref().map(|arguments| {
|
||||
let arguments_init = arguments.as_ref().map(|arguments| {
|
||||
let arg_type = self.args_name();
|
||||
arg_calls = Some(arguments.emit_visit_map(&self.type_, &self.space));
|
||||
let arg_names = arguments.fields.iter().map(|arg| &arg.name);
|
||||
|
@ -262,7 +298,7 @@ impl InstructionVariant {
|
|||
}
|
||||
});
|
||||
quote! {
|
||||
#enum_ :: #name { #data #arguments } => {
|
||||
#enum_ :: #name { #data #arguments_ident } => {
|
||||
#arg_calls
|
||||
#enum_ :: #name { #data #arguments_init }
|
||||
}
|
||||
|
@ -272,7 +308,8 @@ impl InstructionVariant {
|
|||
|
||||
fn emit_type(&self, vis: &Option<Visibility>, tokens: &mut TokenStream) {
|
||||
let arguments = match self.arguments {
|
||||
Some(ref a) => a,
|
||||
Some(Arguments::Def(ref a)) => a,
|
||||
Some(Arguments::Decl(_)) => return,
|
||||
None => return,
|
||||
};
|
||||
let name = self.args_name();
|
||||
|
@ -301,12 +338,18 @@ impl Parse for InstructionVariant {
|
|||
let mut space = None;
|
||||
let mut data = None;
|
||||
let mut arguments = None;
|
||||
let mut visit = None;
|
||||
let mut visit_mut = None;
|
||||
let mut map = None;
|
||||
for property in properties {
|
||||
match property {
|
||||
VariantProperty::Type(t) => type_ = Some(t),
|
||||
VariantProperty::Space(s) => space = Some(s),
|
||||
VariantProperty::Data(d) => data = Some(d),
|
||||
VariantProperty::Arguments(a) => arguments = Some(a),
|
||||
VariantProperty::Visit(e) => visit = Some(e),
|
||||
VariantProperty::VisitMut(e) => visit_mut = Some(e),
|
||||
VariantProperty::Map(e) => map = Some(e),
|
||||
}
|
||||
}
|
||||
Ok(Self {
|
||||
|
@ -315,6 +358,9 @@ impl Parse for InstructionVariant {
|
|||
space,
|
||||
data,
|
||||
arguments,
|
||||
visit,
|
||||
visit_mut,
|
||||
map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +369,10 @@ enum VariantProperty {
|
|||
Type(Option<Expr>),
|
||||
Space(Expr),
|
||||
Data(Type),
|
||||
Arguments(InstructionArguments),
|
||||
Arguments(Arguments),
|
||||
Visit(Expr),
|
||||
VisitMut(Expr),
|
||||
Map(Expr),
|
||||
}
|
||||
|
||||
impl VariantProperty {
|
||||
|
@ -360,15 +409,33 @@ impl VariantProperty {
|
|||
None
|
||||
};
|
||||
input.parse::<Token![:]>()?;
|
||||
let fields;
|
||||
braced!(fields in input);
|
||||
VariantProperty::Arguments(InstructionArguments::parse(generics, &fields)?)
|
||||
if input.peek(token::Brace) {
|
||||
let fields;
|
||||
braced!(fields in input);
|
||||
VariantProperty::Arguments(Arguments::Def(InstructionArguments::parse(
|
||||
generics, &fields,
|
||||
)?))
|
||||
} else {
|
||||
VariantProperty::Arguments(Arguments::Decl(input.parse::<Type>()?))
|
||||
}
|
||||
}
|
||||
"visit" => {
|
||||
input.parse::<Token![:]>()?;
|
||||
VariantProperty::Visit(input.parse::<Expr>()?)
|
||||
}
|
||||
"visit_mut" => {
|
||||
input.parse::<Token![:]>()?;
|
||||
VariantProperty::VisitMut(input.parse::<Expr>()?)
|
||||
}
|
||||
"map" => {
|
||||
input.parse::<Token![:]>()?;
|
||||
VariantProperty::Map(input.parse::<Expr>()?)
|
||||
}
|
||||
x => {
|
||||
return Err(syn::Error::new(
|
||||
key.span(),
|
||||
format!(
|
||||
"Unexpected key `{}`. Expected `type`, `data` or `arguments`.",
|
||||
"Unexpected key `{}`. Expected `type`, `data`, `arguments`, `visit, `visit_mut` or `map`.",
|
||||
x
|
||||
),
|
||||
))
|
||||
|
@ -380,6 +447,11 @@ impl VariantProperty {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Arguments {
|
||||
Decl(Type),
|
||||
Def(InstructionArguments),
|
||||
}
|
||||
|
||||
pub struct InstructionArguments {
|
||||
pub generic: Option<Punctuated<PathSegment, syn::token::PathSep>>,
|
||||
pub fields: Punctuated<ArgumentField, Token![,]>,
|
||||
|
@ -453,7 +525,7 @@ pub struct ArgumentField {
|
|||
impl ArgumentField {
|
||||
fn parse_block(
|
||||
input: syn::parse::ParseStream,
|
||||
) -> syn::Result<(Type, Option<Expr>, Option<Expr>)> {
|
||||
) -> syn::Result<(Type, Option<Expr>, Option<Expr>, Option<bool>)> {
|
||||
let content;
|
||||
braced!(content in input);
|
||||
let all_fields =
|
||||
|
@ -469,6 +541,10 @@ impl ArgumentField {
|
|||
match &*name_ident.to_string() {
|
||||
"repr" => ExprOrPath::Repr(content.parse::<Type>()?),
|
||||
"space" => ExprOrPath::Space(content.parse::<Expr>()?),
|
||||
"dst" => {
|
||||
let ident = content.parse::<LitBool>()?;
|
||||
ExprOrPath::Dst(ident.value)
|
||||
}
|
||||
name => {
|
||||
return Err(syn::Error::new(
|
||||
name_ident.span(),
|
||||
|
@ -483,14 +559,16 @@ impl ArgumentField {
|
|||
let mut repr = None;
|
||||
let mut type_ = None;
|
||||
let mut space = None;
|
||||
let mut is_dst = None;
|
||||
for exp_or_path in all_fields {
|
||||
match exp_or_path {
|
||||
ExprOrPath::Repr(r) => repr = Some(r),
|
||||
ExprOrPath::Type(t) => type_ = Some(t),
|
||||
ExprOrPath::Space(s) => space = Some(s),
|
||||
ExprOrPath::Dst(x) => is_dst = Some(x),
|
||||
}
|
||||
}
|
||||
Ok((repr.unwrap(), type_, space))
|
||||
Ok((repr.unwrap(), type_, space, is_dst))
|
||||
}
|
||||
|
||||
fn parse_basic(input: &syn::parse::ParseBuffer) -> syn::Result<Type> {
|
||||
|
@ -666,16 +744,20 @@ impl ArgumentField {
|
|||
impl Parse for ArgumentField {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let name = input.parse::<Ident>()?;
|
||||
let is_dst = Self::is_dst(&name)?;
|
||||
|
||||
input.parse::<Token![:]>()?;
|
||||
let lookahead = input.lookahead1();
|
||||
let (repr, type_, space) = if lookahead.peek(token::Brace) {
|
||||
let (repr, type_, space, is_dst) = if lookahead.peek(token::Brace) {
|
||||
Self::parse_block(input)?
|
||||
} else if lookahead.peek(syn::Ident) {
|
||||
(Self::parse_basic(input)?, None, None)
|
||||
(Self::parse_basic(input)?, None, None, None)
|
||||
} else {
|
||||
return Err(lookahead.error());
|
||||
};
|
||||
let is_dst = match is_dst {
|
||||
Some(x) => x,
|
||||
None => Self::is_dst(&name)?,
|
||||
};
|
||||
Ok(Self {
|
||||
name,
|
||||
is_dst,
|
||||
|
@ -690,6 +772,7 @@ enum ExprOrPath {
|
|||
Repr(Type),
|
||||
Type(Expr),
|
||||
Space(Expr),
|
||||
Dst(bool),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -140,6 +140,13 @@ gen::generate_instruction_type!(
|
|||
src: T
|
||||
}
|
||||
},
|
||||
Call {
|
||||
data: CallDetails,
|
||||
arguments: CallArgs<T>,
|
||||
visit: arguments.visit(data, visitor),
|
||||
visit_mut: arguments.visit_mut(data, visitor),
|
||||
map: Instruction::Call{ arguments: arguments.map(&data, visitor), data }
|
||||
},
|
||||
Ret {
|
||||
data: RetData
|
||||
},
|
||||
|
@ -154,42 +161,66 @@ pub trait Visitor<T: Operand> {
|
|||
|
||||
pub trait VisitorMut<T: Operand> {
|
||||
fn visit(&mut self, args: &mut T, type_space: Option<(&Type, StateSpace)>, is_dst: bool);
|
||||
fn visit_ident(&mut self, args: &mut T::Ident, type_space: Option<(&Type, StateSpace)>, is_dst: bool);
|
||||
fn visit_ident(
|
||||
&mut self,
|
||||
args: &mut T::Ident,
|
||||
type_space: Option<(&Type, StateSpace)>,
|
||||
is_dst: bool,
|
||||
);
|
||||
}
|
||||
|
||||
pub trait VisitorMap<From: Operand, To: Operand> {
|
||||
fn visit(&mut self, args: From, type_space: Option<(&Type, StateSpace)>, is_dst: bool) -> To;
|
||||
fn visit_ident(&mut self, args: From::Ident, type_space: Option<(&Type, StateSpace)>, is_dst: bool) -> To::Ident;
|
||||
fn visit_ident(
|
||||
&mut self,
|
||||
args: From::Ident,
|
||||
type_space: Option<(&Type, StateSpace)>,
|
||||
is_dst: bool,
|
||||
) -> To::Ident;
|
||||
}
|
||||
|
||||
trait VisitOperand {
|
||||
type Operand: Operand;
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn visit(&self, fn_: impl FnOnce(&Self::Operand));
|
||||
fn visit(&self, fn_: impl FnMut(&Self::Operand));
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn visit_mut(&mut self, fn_: impl FnOnce(&mut Self::Operand));
|
||||
fn visit_mut(&mut self, fn_: impl FnMut(&mut Self::Operand));
|
||||
}
|
||||
|
||||
impl<T: Operand> VisitOperand for T {
|
||||
type Operand = Self;
|
||||
fn visit(&self, fn_: impl FnOnce(&Self::Operand)) {
|
||||
fn visit(&self, mut fn_: impl FnMut(&Self::Operand)) {
|
||||
fn_(self)
|
||||
}
|
||||
fn visit_mut(&mut self, fn_: impl FnOnce(&mut Self::Operand)) {
|
||||
fn visit_mut(&mut self, mut fn_: impl FnMut(&mut Self::Operand)) {
|
||||
fn_(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Operand> VisitOperand for Option<T> {
|
||||
type Operand = T;
|
||||
fn visit(&self, fn_: impl FnOnce(&Self::Operand)) {
|
||||
fn visit(&self, fn_: impl FnMut(&Self::Operand)) {
|
||||
self.as_ref().map(fn_);
|
||||
}
|
||||
fn visit_mut(&mut self, fn_: impl FnOnce(&mut Self::Operand)) {
|
||||
fn visit_mut(&mut self, fn_: impl FnMut(&mut Self::Operand)) {
|
||||
self.as_mut().map(fn_);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Operand> VisitOperand for Vec<T> {
|
||||
type Operand = T;
|
||||
fn visit(&self, mut fn_: impl FnMut(&Self::Operand)) {
|
||||
for o in self {
|
||||
fn_(o)
|
||||
}
|
||||
}
|
||||
fn visit_mut(&mut self, mut fn_: impl FnMut(&mut Self::Operand)) {
|
||||
for o in self {
|
||||
fn_(o)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait MapOperand: Sized {
|
||||
type Input;
|
||||
type Output<U>;
|
||||
|
@ -649,3 +680,65 @@ impl From<RawSetpCompareOp> for SetpCompareFloat {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallDetails {
|
||||
uniform: bool,
|
||||
ret_params: Vec<(Type, StateSpace)>,
|
||||
param_list: Vec<(Type, StateSpace)>,
|
||||
}
|
||||
|
||||
pub struct CallArgs<T: Operand> {
|
||||
pub ret_params: Vec<T::Ident>,
|
||||
pub func: T::Ident,
|
||||
pub param_list: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: Operand> CallArgs<T> {
|
||||
#[allow(dead_code)] // Used by generated code
|
||||
fn visit(&self, details: &CallDetails, visitor: &mut impl Visitor<T>) {
|
||||
for (param, (type_, space)) in self.ret_params.iter().zip(details.ret_params.iter()) {
|
||||
visitor.visit_ident(param, Some((type_, *space)), true);
|
||||
}
|
||||
visitor.visit_ident(&self.func, None, false);
|
||||
for (param, (type_, space)) in self.param_list.iter().zip(details.param_list.iter()) {
|
||||
visitor.visit(param, Some((type_, *space)), true);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by generated code
|
||||
fn visit_mut(&mut self, details: &CallDetails, visitor: &mut impl VisitorMut<T>) {
|
||||
for (param, (type_, space)) in self.ret_params.iter_mut().zip(details.ret_params.iter()) {
|
||||
visitor.visit_ident(param, Some((type_, *space)), true);
|
||||
}
|
||||
visitor.visit_ident(&mut self.func, None, false);
|
||||
for (param, (type_, space)) in self.param_list.iter_mut().zip(details.param_list.iter()) {
|
||||
visitor.visit(param, Some((type_, *space)), true);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by generated code
|
||||
fn map<U: Operand>(
|
||||
self,
|
||||
details: &CallDetails,
|
||||
visitor: &mut impl VisitorMap<T, U>,
|
||||
) -> CallArgs<U> {
|
||||
let ret_params = self
|
||||
.ret_params
|
||||
.into_iter()
|
||||
.zip(details.ret_params.iter())
|
||||
.map(|(param, (type_, space))| visitor.visit_ident(param, Some((type_, *space)), true))
|
||||
.collect::<Vec<_>>();
|
||||
let func = visitor.visit_ident(self.func, None, false);
|
||||
let param_list = self
|
||||
.param_list
|
||||
.into_iter()
|
||||
.zip(details.param_list.iter())
|
||||
.map(|(param, (type_, space))| visitor.visit(param, Some((type_, *space)), true))
|
||||
.collect::<Vec<_>>();
|
||||
CallArgs {
|
||||
ret_params,
|
||||
func,
|
||||
param_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue