mirror of
https://github.com/vosen/ZLUDA.git
synced 2025-04-20 00:14:45 +00:00
Implement not, or, and, bra
This commit is contained in:
parent
c08e6a6772
commit
22492ec7f1
5 changed files with 316 additions and 119 deletions
|
@ -231,7 +231,8 @@ impl SingleOpcodeDefinition {
|
|||
}
|
||||
|
||||
fn extract_and_insert(
|
||||
output: &mut FxHashMap<Ident, Vec<SingleOpcodeDefinition>>,
|
||||
definitions: &mut FxHashMap<Ident, Vec<SingleOpcodeDefinition>>,
|
||||
special_definitions: &mut FxHashMap<Ident, proc_macro2::Group>,
|
||||
parser::OpcodeDefinition(pattern_seq, rules): parser::OpcodeDefinition,
|
||||
) {
|
||||
let (mut named_rules, mut unnamed_rules) = gather_rules(rules);
|
||||
|
@ -242,8 +243,18 @@ impl SingleOpcodeDefinition {
|
|||
named_rules = FxHashMap::default();
|
||||
unnamed_rules = FxHashMap::default();
|
||||
}
|
||||
let mut possible_modifiers = FxHashSet::default();
|
||||
let parser::OpcodeDecl(instruction, arguments) = opcode_decl;
|
||||
if code_block.special {
|
||||
if !instruction.modifiers.is_empty() || !arguments.0.is_empty() {
|
||||
panic!(
|
||||
"`{}`: no modifiers or arguments are allowed in parser definition.",
|
||||
instruction.name
|
||||
);
|
||||
}
|
||||
special_definitions.insert(instruction.name, code_block.code);
|
||||
continue;
|
||||
}
|
||||
let mut possible_modifiers = FxHashSet::default();
|
||||
let mut unordered_modifiers = instruction
|
||||
.modifiers
|
||||
.into_iter()
|
||||
|
@ -287,7 +298,7 @@ impl SingleOpcodeDefinition {
|
|||
arguments,
|
||||
code_block,
|
||||
};
|
||||
multihash_extend(output, current_opcode.clone(), entry);
|
||||
multihash_extend(definitions, current_opcode.clone(), entry);
|
||||
last_opcode = current_opcode;
|
||||
}
|
||||
}
|
||||
|
@ -350,10 +361,15 @@ fn gather_rules(
|
|||
pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let parse_definitions = parse_macro_input!(tokens as gen_impl::parser::ParseDefinitions);
|
||||
let mut definitions = FxHashMap::default();
|
||||
let mut special_definitions = FxHashMap::default();
|
||||
let types = OpcodeDefinitions::get_enum_types(&parse_definitions.definitions);
|
||||
let enum_types_tokens = emit_enum_types(types, parse_definitions.additional_enums);
|
||||
for definition in parse_definitions.definitions.into_iter() {
|
||||
SingleOpcodeDefinition::extract_and_insert(&mut definitions, definition);
|
||||
SingleOpcodeDefinition::extract_and_insert(
|
||||
&mut definitions,
|
||||
&mut special_definitions,
|
||||
definition,
|
||||
);
|
||||
}
|
||||
let definitions = definitions
|
||||
.into_iter()
|
||||
|
@ -363,9 +379,12 @@ pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
|
|||
})
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
let mut token_enum = parse_definitions.token_type;
|
||||
let (all_opcode, all_modifier) =
|
||||
write_definitions_into_tokens(&definitions, &mut token_enum.variants);
|
||||
let token_impl = emit_parse_function(&token_enum.ident, &definitions, all_opcode, all_modifier);
|
||||
let (all_opcode, all_modifier) = write_definitions_into_tokens(
|
||||
&definitions,
|
||||
special_definitions.keys(),
|
||||
&mut token_enum.variants,
|
||||
);
|
||||
let token_impl = emit_parse_function(&token_enum.ident, &definitions, &special_definitions, all_opcode, all_modifier);
|
||||
let tokens = quote! {
|
||||
#enum_types_tokens
|
||||
|
||||
|
@ -422,6 +441,7 @@ fn emit_enum_types(
|
|||
fn emit_parse_function(
|
||||
type_name: &Ident,
|
||||
defs: &FxHashMap<Ident, OpcodeDefinitions>,
|
||||
special_defs: &FxHashMap<Ident, proc_macro2::Group>,
|
||||
all_opcode: Vec<&Ident>,
|
||||
all_modifier: FxHashSet<&parser::DotModifier>,
|
||||
) -> TokenStream {
|
||||
|
@ -433,7 +453,7 @@ fn emit_parse_function(
|
|||
let mut fn_name = opcode.to_string();
|
||||
write!(&mut fn_name, "_{}", idx).ok();
|
||||
let fn_name = Ident::new(&fn_name, Span::call_site());
|
||||
let code_block = &def.code_block.0;
|
||||
let code_block = &def.code_block.code;
|
||||
let args = def.function_arguments_declarations();
|
||||
quote! {
|
||||
fn #fn_name<'input>(state: &mut PtxParserState, #(#args),* ) -> Instruction<ParsedOperandStr<'input>> #code_block
|
||||
|
@ -494,7 +514,12 @@ fn emit_parse_function(
|
|||
}
|
||||
.to_tokens(&mut result);
|
||||
result
|
||||
});
|
||||
}).chain(special_defs.iter().map(|(opcode, code)| {
|
||||
let opcode_variant = Ident::new(&capitalize(&opcode.to_string()), opcode.span());
|
||||
quote! {
|
||||
#opcode_variant => { #code? }
|
||||
}
|
||||
}));
|
||||
let opcodes = all_opcode.into_iter().map(|op_ident| {
|
||||
let op = op_ident.to_string();
|
||||
let variant = Ident::new(&capitalize(&op), op_ident.span());
|
||||
|
@ -749,7 +774,7 @@ fn emit_definition_parser(
|
|||
};
|
||||
let pre_pipe = if arg.pre_pipe {
|
||||
quote! {
|
||||
any.verify(|t| *t == #token_type::Or).void()
|
||||
any.verify(|t| *t == #token_type::Pipe).void()
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
|
@ -845,6 +870,7 @@ fn emit_definition_parser(
|
|||
|
||||
fn write_definitions_into_tokens<'a>(
|
||||
defs: &'a FxHashMap<Ident, OpcodeDefinitions>,
|
||||
special_definitions: impl Iterator<Item = &'a Ident>,
|
||||
variants: &mut Punctuated<Variant, Token![,]>,
|
||||
) -> (Vec<&'a Ident>, FxHashSet<&'a parser::DotModifier>) {
|
||||
let mut all_opcodes = Vec::new();
|
||||
|
@ -864,6 +890,16 @@ fn write_definitions_into_tokens<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
for opcode in special_definitions {
|
||||
all_opcodes.push(opcode);
|
||||
let opcode_as_string = opcode.to_string();
|
||||
let variant_name = Ident::new(&capitalize(&opcode_as_string), opcode.span());
|
||||
let arg: Variant = syn::parse_quote! {
|
||||
#[token(#opcode_as_string)]
|
||||
#variant_name
|
||||
};
|
||||
variants.push(arg);
|
||||
}
|
||||
for modifier in all_modifiers.iter() {
|
||||
let modifier_as_string = modifier.to_string();
|
||||
let variant_name = modifier.dot_capitalized();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{
|
||||
braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, Token, Type, TypeParam,
|
||||
Visibility,
|
||||
braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, PathSegment, Token, Type,
|
||||
TypeParam, Visibility,
|
||||
};
|
||||
|
||||
pub mod parser;
|
||||
|
@ -18,7 +18,7 @@ pub struct GenerateInstructionType {
|
|||
impl GenerateInstructionType {
|
||||
pub fn emit_arg_types(&self, tokens: &mut TokenStream) {
|
||||
for v in self.variants.iter() {
|
||||
v.emit_type(&self.visibility, &self.type_parameters, tokens);
|
||||
v.emit_type(&self.visibility, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ impl Parse for GenerateInstructionType {
|
|||
|
||||
pub struct InstructionVariant {
|
||||
pub name: Ident,
|
||||
pub type_: Option<Expr>,
|
||||
pub type_: Option<Option<Expr>>,
|
||||
pub space: Option<Expr>,
|
||||
pub data: Option<Type>,
|
||||
pub arguments: Option<InstructionArguments>,
|
||||
|
@ -225,7 +225,7 @@ impl InstructionVariant {
|
|||
&self,
|
||||
enum_: &Ident,
|
||||
tokens: &mut TokenStream,
|
||||
mut fn_: impl FnMut(&InstructionArguments, &Option<Expr>, &Option<Expr>) -> TokenStream,
|
||||
mut fn_: impl FnMut(&InstructionArguments, &Option<Option<Expr>>, &Option<Expr>) -> TokenStream,
|
||||
) {
|
||||
let name = &self.name;
|
||||
let arguments = match &self.arguments {
|
||||
|
@ -238,9 +238,10 @@ impl InstructionVariant {
|
|||
}
|
||||
Some(args) => args,
|
||||
};
|
||||
let data = &self.data.as_ref().map(|_| quote! { data,});
|
||||
let arg_calls = fn_(arguments, &self.type_, &self.space);
|
||||
quote! {
|
||||
#enum_ :: #name { arguments, data } => {
|
||||
#enum_ :: #name { #data arguments } => {
|
||||
#arg_calls
|
||||
}
|
||||
}
|
||||
|
@ -269,19 +270,14 @@ impl InstructionVariant {
|
|||
.to_tokens(tokens);
|
||||
}
|
||||
|
||||
fn emit_type(
|
||||
&self,
|
||||
vis: &Option<Visibility>,
|
||||
type_parameters: &Punctuated<TypeParam, Token![,]>,
|
||||
tokens: &mut TokenStream,
|
||||
) {
|
||||
fn emit_type(&self, vis: &Option<Visibility>, tokens: &mut TokenStream) {
|
||||
let arguments = match self.arguments {
|
||||
Some(ref a) => a,
|
||||
None => return,
|
||||
};
|
||||
let name = self.args_name();
|
||||
let type_parameters = if arguments.generic.is_some() {
|
||||
Some(quote! { <#type_parameters> })
|
||||
Some(quote! { <T> })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -324,7 +320,7 @@ impl Parse for InstructionVariant {
|
|||
}
|
||||
|
||||
enum VariantProperty {
|
||||
Type(Expr),
|
||||
Type(Option<Expr>),
|
||||
Space(Expr),
|
||||
Data(Type),
|
||||
Arguments(InstructionArguments),
|
||||
|
@ -336,7 +332,12 @@ impl VariantProperty {
|
|||
Ok(if lookahead.peek(Token![type]) {
|
||||
input.parse::<Token![type]>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
VariantProperty::Type(input.parse::<Expr>()?)
|
||||
VariantProperty::Type(if input.peek(Token![!]) {
|
||||
input.parse::<Token![!]>()?;
|
||||
None
|
||||
} else {
|
||||
Some(input.parse::<Expr>()?)
|
||||
})
|
||||
} else if lookahead.peek(Ident) {
|
||||
let key = input.parse::<Ident>()?;
|
||||
match &*key.to_string() {
|
||||
|
@ -352,7 +353,7 @@ impl VariantProperty {
|
|||
let generics = if input.peek(Token![<]) {
|
||||
input.parse::<Token![<]>()?;
|
||||
let gen_params =
|
||||
Punctuated::<TypeParam, Token![,]>::parse_separated_nonempty(input)?;
|
||||
Punctuated::<PathSegment, syn::token::PathSep>::parse_separated_nonempty(input)?;
|
||||
input.parse::<Token![>]>()?;
|
||||
Some(gen_params)
|
||||
} else {
|
||||
|
@ -380,13 +381,13 @@ impl VariantProperty {
|
|||
}
|
||||
|
||||
pub struct InstructionArguments {
|
||||
pub generic: Option<Punctuated<TypeParam, Token![,]>>,
|
||||
pub generic: Option<Punctuated<PathSegment, syn::token::PathSep>>,
|
||||
pub fields: Punctuated<ArgumentField, Token![,]>,
|
||||
}
|
||||
|
||||
impl InstructionArguments {
|
||||
pub fn parse(
|
||||
generic: Option<Punctuated<TypeParam, Token![,]>>,
|
||||
generic: Option<Punctuated<PathSegment, syn::token::PathSep>>,
|
||||
input: syn::parse::ParseStream,
|
||||
) -> syn::Result<Self> {
|
||||
let fields = Punctuated::<ArgumentField, Token![,]>::parse_terminated_with(
|
||||
|
@ -396,13 +397,17 @@ impl InstructionArguments {
|
|||
Ok(Self { generic, fields })
|
||||
}
|
||||
|
||||
fn emit_visit(&self, parent_type: &Option<Expr>, parent_space: &Option<Expr>) -> TokenStream {
|
||||
fn emit_visit(
|
||||
&self,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit)
|
||||
}
|
||||
|
||||
fn emit_visit_mut(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_mut)
|
||||
|
@ -410,7 +415,7 @@ impl InstructionArguments {
|
|||
|
||||
fn emit_visit_map(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_map)
|
||||
|
@ -418,14 +423,19 @@ impl InstructionArguments {
|
|||
|
||||
fn emit_visit_impl(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
mut fn_: impl FnMut(&ArgumentField, &Option<Expr>, &Option<Expr>) -> TokenStream,
|
||||
mut fn_: impl FnMut(&ArgumentField, &Option<Option<Expr>>, &Option<Expr>, bool) -> TokenStream,
|
||||
) -> TokenStream {
|
||||
let is_ident = if let Some(ref generic) = self.generic {
|
||||
generic.len() > 1
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let field_calls = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| fn_(f, parent_type, parent_space));
|
||||
.map(|f| fn_(f, parent_type, parent_space, is_ident));
|
||||
quote! {
|
||||
#(#field_calls)*
|
||||
}
|
||||
|
@ -487,25 +497,37 @@ impl ArgumentField {
|
|||
input.parse::<Type>()
|
||||
}
|
||||
|
||||
fn emit_visit(&self, parent_type: &Option<Expr>, parent_space: &Option<Expr>) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, false)
|
||||
fn emit_visit(
|
||||
&self,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
is_ident: bool,
|
||||
) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, is_ident, false)
|
||||
}
|
||||
|
||||
fn emit_visit_mut(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
is_ident: bool,
|
||||
) -> TokenStream {
|
||||
self.emit_visit_impl(parent_type, parent_space, true)
|
||||
self.emit_visit_impl(parent_type, parent_space, is_ident, true)
|
||||
}
|
||||
|
||||
fn emit_visit_impl(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
is_ident: bool,
|
||||
is_mut: bool,
|
||||
) -> TokenStream {
|
||||
let type_ = self.type_.as_ref().or(parent_type.as_ref()).unwrap();
|
||||
let (is_typeless, type_) = match (self.type_.as_ref(), parent_type) {
|
||||
(Some(type_), _) => (false, Some(type_)),
|
||||
(None, None) => panic!("No type set"),
|
||||
(None, Some(None)) => (true, None),
|
||||
(None, Some(Some(type_))) => (false, Some(type_)),
|
||||
};
|
||||
let space = self
|
||||
.space
|
||||
.as_ref()
|
||||
|
@ -514,38 +536,72 @@ impl ArgumentField {
|
|||
.unwrap_or_else(|| quote! { StateSpace::Reg });
|
||||
let is_dst = self.is_dst;
|
||||
let name = &self.name;
|
||||
let (operand_fn, arguments_name) = if is_mut {
|
||||
(
|
||||
quote! {
|
||||
VisitOperand::visit_mut
|
||||
},
|
||||
quote! {
|
||||
&mut arguments.#name
|
||||
},
|
||||
)
|
||||
let type_space = if is_typeless {
|
||||
quote! {
|
||||
let type_space = None;
|
||||
}
|
||||
} else {
|
||||
(
|
||||
quote! {
|
||||
VisitOperand::visit
|
||||
},
|
||||
quote! {
|
||||
& arguments.#name
|
||||
},
|
||||
)
|
||||
quote! {
|
||||
let type_ = #type_;
|
||||
let space = #space;
|
||||
let type_space = Some((std::borrow::Borrow::<Type>::borrow(&type_), space));
|
||||
}
|
||||
};
|
||||
quote! {{
|
||||
let type_ = #type_;
|
||||
let space = #space;
|
||||
#operand_fn(#arguments_name, |x| visitor.visit(x, &type_, space, #is_dst));
|
||||
}}
|
||||
if is_ident {
|
||||
if is_mut {
|
||||
quote! {
|
||||
{
|
||||
#type_space
|
||||
visitor.visit_ident(&mut arguments.#name, type_space, #is_dst);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
{
|
||||
#type_space
|
||||
visitor.visit_ident(& arguments.#name, type_space, #is_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (operand_fn, arguments_name) = if is_mut {
|
||||
(
|
||||
quote! {
|
||||
VisitOperand::visit_mut
|
||||
},
|
||||
quote! {
|
||||
&mut arguments.#name
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(
|
||||
quote! {
|
||||
VisitOperand::visit
|
||||
},
|
||||
quote! {
|
||||
& arguments.#name
|
||||
},
|
||||
)
|
||||
};
|
||||
quote! {{
|
||||
#type_space
|
||||
#operand_fn(#arguments_name, |x| visitor.visit(x, type_space, #is_dst));
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_visit_map(
|
||||
&self,
|
||||
parent_type: &Option<Expr>,
|
||||
parent_type: &Option<Option<Expr>>,
|
||||
parent_space: &Option<Expr>,
|
||||
is_ident: bool,
|
||||
) -> TokenStream {
|
||||
let type_ = self.type_.as_ref().or(parent_type.as_ref()).unwrap();
|
||||
let (is_typeless, type_) = match (self.type_.as_ref(), parent_type) {
|
||||
(Some(type_), _) => (false, Some(type_)),
|
||||
(None, None) => panic!("No type set"),
|
||||
(None, Some(None)) => (true, None),
|
||||
(None, Some(Some(type_))) => (false, Some(type_)),
|
||||
};
|
||||
let space = self
|
||||
.space
|
||||
.as_ref()
|
||||
|
@ -554,11 +610,30 @@ impl ArgumentField {
|
|||
.unwrap_or_else(|| quote! { StateSpace::Reg });
|
||||
let is_dst = self.is_dst;
|
||||
let name = &self.name;
|
||||
quote! {
|
||||
let #name = {
|
||||
let type_space = if is_typeless {
|
||||
quote! {
|
||||
let type_space = None;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let type_ = #type_;
|
||||
let space = #space;
|
||||
MapOperand::map(arguments.#name, |x| visitor.visit(x, &type_, space, #is_dst))
|
||||
let type_space = Some((std::borrow::Borrow::<Type>::borrow(&type_), space));
|
||||
}
|
||||
};
|
||||
let map_call = if is_ident {
|
||||
quote! {
|
||||
visitor.visit_ident(arguments.#name, type_space, #is_dst)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
MapOperand::map(arguments.#name, |x| visitor.visit(x, type_space, #is_dst))
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
let #name = {
|
||||
#type_space
|
||||
#map_call
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -702,27 +777,6 @@ mod tests {
|
|||
assert!(matches!(src.space, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn visit_variant() {
|
||||
let input = quote! {
|
||||
Ld {
|
||||
type: ScalarType::U32,
|
||||
data: LdDetails,
|
||||
arguments<P>: {
|
||||
dst: {
|
||||
repr: P::Operand,
|
||||
type: ScalarType::U32
|
||||
},
|
||||
src: P::Operand,
|
||||
},
|
||||
}
|
||||
};
|
||||
let variant = syn::parse2::<InstructionVariant>(input).unwrap();
|
||||
let mut output = TokenStream::new();
|
||||
variant.emit_visit(&Ident::new("Instruction", Span::call_site()), &mut output);
|
||||
assert_eq!(output.to_string(), "Instruction :: Ld { arguments , data } => { { let type_ = ScalarType :: U32 ; let space = StateSpace :: Reg ; visitor . visit (& arguments . dst , & type_ , space , true) ; } { let type_ = ScalarType :: U32 ; let space = StateSpace :: Reg ; visitor . visit (& arguments . src , & type_ , space , false) ; } }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn visit_variant_empty() {
|
||||
let input = quote! {
|
||||
|
|
|
@ -86,13 +86,27 @@ impl Parse for OpcodeDecl {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CodeBlock(pub proc_macro2::Group);
|
||||
pub struct CodeBlock {
|
||||
pub special: bool,
|
||||
pub code: proc_macro2::Group,
|
||||
}
|
||||
|
||||
impl Parse for CodeBlock {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
input.parse::<Token![=>]>()?;
|
||||
let group = input.parse::<proc_macro2::Group>()?;
|
||||
Ok(Self(group))
|
||||
let lookahead = input.lookahead1();
|
||||
let (special, code) = if lookahead.peek(Token![<]) {
|
||||
input.parse::<Token![<]>()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
//input.parse::<Token![>]>()?;
|
||||
(true, input.parse::<proc_macro2::Group>()?)
|
||||
} else if lookahead.peek(Token![=]) {
|
||||
input.parse::<Token![=]>()?;
|
||||
input.parse::<Token![>]>()?;
|
||||
(false, input.parse::<proc_macro2::Group>()?)
|
||||
} else {
|
||||
return Err(lookahead.error());
|
||||
};
|
||||
Ok(Self{special, code})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,7 +775,7 @@ mod tests {
|
|||
.ss: StateSpace = { .global, .local, .param{::func}, .shared{::cta, ::cluster} }
|
||||
};
|
||||
let rule = syn::parse2::<super::Rule>(input).unwrap();
|
||||
assert_eq!(". ss", rule.modifier.tokens().to_string());
|
||||
assert_eq!(". ss", rule.modifier.unwrap().tokens().to_string());
|
||||
assert_eq!(
|
||||
"StateSpace",
|
||||
rule.type_.unwrap().to_token_stream().to_string()
|
||||
|
@ -791,7 +805,7 @@ mod tests {
|
|||
.cop: StCacheOperator = { .wb, .cg, .cs, .wt }
|
||||
};
|
||||
let rule = syn::parse2::<super::Rule>(input).unwrap();
|
||||
assert_eq!(". cop", rule.modifier.tokens().to_string());
|
||||
assert_eq!(". cop", rule.modifier.unwrap().tokens().to_string());
|
||||
assert_eq!(
|
||||
"StCacheOperator",
|
||||
rule.type_.unwrap().to_token_stream().to_string()
|
||||
|
@ -819,4 +833,12 @@ mod tests {
|
|||
assert!(!a.can_be_negated);
|
||||
assert!(a.unified);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn special_block() {
|
||||
let input = quote! {
|
||||
bra <= { bra(stream) }
|
||||
};
|
||||
syn::parse2::<super::OpcodeDefinition>(input).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ gen::generate_instruction_type!(
|
|||
}
|
||||
},
|
||||
Add {
|
||||
type: { data.type_().into() },
|
||||
type: { Type::from(data.type_()) },
|
||||
data: ArithDetails,
|
||||
arguments<T>: {
|
||||
dst: T,
|
||||
|
@ -51,12 +51,12 @@ gen::generate_instruction_type!(
|
|||
}
|
||||
},
|
||||
Mul {
|
||||
type: { data.type_().into() },
|
||||
type: { Type::from(data.type_()) },
|
||||
data: MulDetails,
|
||||
arguments<T>: {
|
||||
dst: {
|
||||
repr: T,
|
||||
type: { data.dst_type().into() },
|
||||
type: { Type::from(data.dst_type()) },
|
||||
},
|
||||
src1: T,
|
||||
src2: T,
|
||||
|
@ -67,19 +67,19 @@ gen::generate_instruction_type!(
|
|||
arguments<T>: {
|
||||
dst1: {
|
||||
repr: T,
|
||||
type: ScalarType::Pred.into()
|
||||
type: Type::from(ScalarType::Pred)
|
||||
},
|
||||
dst2: {
|
||||
repr: Option<T>,
|
||||
type: ScalarType::Pred.into()
|
||||
type: Type::from(ScalarType::Pred)
|
||||
},
|
||||
src1: {
|
||||
repr: T,
|
||||
type: data.type_.into(),
|
||||
type: Type::from(data.type_),
|
||||
},
|
||||
src2: {
|
||||
repr: T,
|
||||
type: data.type_.into(),
|
||||
type: Type::from(data.type_),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -88,26 +88,58 @@ gen::generate_instruction_type!(
|
|||
arguments<T>: {
|
||||
dst1: {
|
||||
repr: T,
|
||||
type: ScalarType::Pred.into()
|
||||
type: Type::from(ScalarType::Pred)
|
||||
},
|
||||
dst2: {
|
||||
repr: Option<T>,
|
||||
type: ScalarType::Pred.into()
|
||||
type: Type::from(ScalarType::Pred)
|
||||
},
|
||||
src1: {
|
||||
repr: T,
|
||||
type: data.base.type_.into(),
|
||||
type: Type::from(data.base.type_),
|
||||
},
|
||||
src2: {
|
||||
repr: T,
|
||||
type: data.base.type_.into(),
|
||||
type: Type::from(data.base.type_),
|
||||
},
|
||||
src3: {
|
||||
repr: T,
|
||||
type: ScalarType::Pred.into()
|
||||
type: Type::from(ScalarType::Pred)
|
||||
}
|
||||
}
|
||||
},
|
||||
Not {
|
||||
data: ScalarType,
|
||||
type: { Type::Scalar(data.clone()) },
|
||||
arguments<T>: {
|
||||
dst: T,
|
||||
src: T,
|
||||
}
|
||||
},
|
||||
Or {
|
||||
data: ScalarType,
|
||||
type: { Type::Scalar(data.clone()) },
|
||||
arguments<T>: {
|
||||
dst: T,
|
||||
src1: T,
|
||||
src2: T,
|
||||
}
|
||||
},
|
||||
And {
|
||||
data: ScalarType,
|
||||
type: { Type::Scalar(data.clone()) },
|
||||
arguments<T>: {
|
||||
dst: T,
|
||||
src1: T,
|
||||
src2: T,
|
||||
}
|
||||
},
|
||||
Bra {
|
||||
type: !,
|
||||
arguments<T::Ident>: {
|
||||
src: T
|
||||
}
|
||||
},
|
||||
Ret {
|
||||
data: RetData
|
||||
},
|
||||
|
@ -115,21 +147,26 @@ gen::generate_instruction_type!(
|
|||
}
|
||||
);
|
||||
|
||||
pub trait Visitor<T> {
|
||||
fn visit(&mut self, args: &T, type_: &Type, space: StateSpace, is_dst: bool);
|
||||
pub trait Visitor<T: Operand> {
|
||||
fn visit(&mut self, args: &T, type_space: Option<(&Type, StateSpace)>, is_dst: bool);
|
||||
fn visit_ident(&self, args: &T::Ident, type_space: Option<(&Type, StateSpace)>, is_dst: bool);
|
||||
}
|
||||
|
||||
pub trait VisitorMut<T> {
|
||||
fn visit(&mut self, args: &mut T, type_: &Type, space: StateSpace, is_dst: bool);
|
||||
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);
|
||||
}
|
||||
|
||||
pub trait VisitorMap<From, To> {
|
||||
fn visit(&mut self, args: From, type_: &Type, space: StateSpace, is_dst: bool) -> To;
|
||||
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;
|
||||
}
|
||||
|
||||
trait VisitOperand {
|
||||
type Operand;
|
||||
type Operand: Operand;
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn visit(&self, fn_: impl FnOnce(&Self::Operand));
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn visit_mut(&mut self, fn_: impl FnOnce(&mut Self::Operand));
|
||||
}
|
||||
|
||||
|
@ -156,6 +193,7 @@ impl<T: Operand> VisitOperand for Option<T> {
|
|||
trait MapOperand: Sized {
|
||||
type Input;
|
||||
type Output<U>;
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn map<U>(self, fn_: impl FnOnce(Self::Input) -> U) -> Self::Output<U>;
|
||||
}
|
||||
|
||||
|
@ -289,12 +327,12 @@ pub enum ParsedOperand<Ident> {
|
|||
VecPack(Vec<Ident>),
|
||||
}
|
||||
|
||||
impl<Ident> Operand for ParsedOperand<Ident> {
|
||||
impl<Ident: Copy> Operand for ParsedOperand<Ident> {
|
||||
type Ident = Ident;
|
||||
}
|
||||
|
||||
pub trait Operand {
|
||||
type Ident;
|
||||
type Ident: Copy;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -447,6 +485,7 @@ pub enum MulDetails {
|
|||
}
|
||||
|
||||
impl MulDetails {
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn type_(&self) -> ScalarType {
|
||||
match self {
|
||||
MulDetails::Integer { type_, .. } => *type_,
|
||||
|
@ -454,6 +493,7 @@ impl MulDetails {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(unused)] // Used by generated code
|
||||
fn dst_type(&self) -> ScalarType {
|
||||
match self {
|
||||
MulDetails::Integer {
|
||||
|
@ -521,7 +561,7 @@ impl SetpData {
|
|||
pub struct SetpBoolData {
|
||||
pub base: SetpData,
|
||||
pub bool_op: SetpBoolPostOp,
|
||||
pub negate_src3: bool
|
||||
pub negate_src3: bool,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
|
|
|
@ -623,7 +623,7 @@ fn predicated_instruction<'a, 'input>(
|
|||
}
|
||||
|
||||
fn pred_at<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<ast::PredAt<&'input str>> {
|
||||
(Token::At, opt(Token::Not), ident)
|
||||
(Token::At, opt(Token::Exclamation), ident)
|
||||
.map(|(_, not, label)| ast::PredAt {
|
||||
not: not.is_some(),
|
||||
label,
|
||||
|
@ -888,6 +888,21 @@ impl<'input, I: Stream<Token = Self> + StreamIsPartial, E: ParserError<I>> Parse
|
|||
}
|
||||
}
|
||||
|
||||
fn bra<'a, 'input>(
|
||||
stream: &mut PtxParser<'a, 'input>,
|
||||
) -> PResult<ast::Instruction<ParsedOperandStr<'input>>> {
|
||||
preceded(
|
||||
opt(Token::DotUni),
|
||||
any.verify_map(|t| match t {
|
||||
Token::Ident(ident) => Some(ast::Instruction::Bra {
|
||||
arguments: BraArgs { src: ident },
|
||||
}),
|
||||
_ => None,
|
||||
}),
|
||||
)
|
||||
.parse_next(stream)
|
||||
}
|
||||
|
||||
// Modifiers are turned into arguments to the blocks, with type:
|
||||
// * If it is an alternative:
|
||||
// * If it is mandatory then its type is Foo (as defined by the relevant rule)
|
||||
|
@ -919,9 +934,9 @@ derive_parser!(
|
|||
#[regex(r#""[^"]*""#)]
|
||||
String,
|
||||
#[token("|")]
|
||||
Or,
|
||||
Pipe,
|
||||
#[token("!")]
|
||||
Not,
|
||||
Exclamation,
|
||||
#[token("(")]
|
||||
LParen,
|
||||
#[token(")")]
|
||||
|
@ -1461,6 +1476,36 @@ derive_parser!(
|
|||
.f32, .f64,
|
||||
.f16, .f16x2, .bf16, .bf16x2 };
|
||||
|
||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#logic-and-shift-instructions-not
|
||||
not.type d, a => {
|
||||
ast::Instruction::Not {
|
||||
data: type_,
|
||||
arguments: NotArgs { dst: d, src: a }
|
||||
}
|
||||
}
|
||||
.type: ScalarType = { .pred, .b16, .b32, .b64 };
|
||||
|
||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#logic-and-shift-instructions-or
|
||||
or.type d, a, b => {
|
||||
ast::Instruction::Or {
|
||||
data: type_,
|
||||
arguments: OrArgs { dst: d, src1: a, src2: b }
|
||||
}
|
||||
}
|
||||
.type: ScalarType = { .pred, .b16, .b32, .b64 };
|
||||
|
||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#logic-and-shift-instructions-and
|
||||
and.type d, a, b => {
|
||||
ast::Instruction::And {
|
||||
data: type_,
|
||||
arguments: AndArgs { dst: d, src1: a, src2: b }
|
||||
}
|
||||
}
|
||||
.type: ScalarType = { .pred, .b16, .b32, .b64 };
|
||||
|
||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#control-flow-instructions-bra
|
||||
bra <= { bra(stream) }
|
||||
|
||||
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#control-flow-instructions-ret
|
||||
ret{.uni} => {
|
||||
Instruction::Ret { data: RetData { uniform: uni } }
|
||||
|
|
Loading…
Add table
Reference in a new issue