Implement not, or, and, bra

This commit is contained in:
Andrzej Janik 2024-08-19 13:37:04 +02:00
commit 22492ec7f1
5 changed files with 316 additions and 119 deletions

View file

@ -231,7 +231,8 @@ impl SingleOpcodeDefinition {
} }
fn extract_and_insert( 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, parser::OpcodeDefinition(pattern_seq, rules): parser::OpcodeDefinition,
) { ) {
let (mut named_rules, mut unnamed_rules) = gather_rules(rules); let (mut named_rules, mut unnamed_rules) = gather_rules(rules);
@ -242,8 +243,18 @@ impl SingleOpcodeDefinition {
named_rules = FxHashMap::default(); named_rules = FxHashMap::default();
unnamed_rules = FxHashMap::default(); unnamed_rules = FxHashMap::default();
} }
let mut possible_modifiers = FxHashSet::default();
let parser::OpcodeDecl(instruction, arguments) = opcode_decl; 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 let mut unordered_modifiers = instruction
.modifiers .modifiers
.into_iter() .into_iter()
@ -287,7 +298,7 @@ impl SingleOpcodeDefinition {
arguments, arguments,
code_block, code_block,
}; };
multihash_extend(output, current_opcode.clone(), entry); multihash_extend(definitions, current_opcode.clone(), entry);
last_opcode = current_opcode; last_opcode = current_opcode;
} }
} }
@ -350,10 +361,15 @@ fn gather_rules(
pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let parse_definitions = parse_macro_input!(tokens as gen_impl::parser::ParseDefinitions); let parse_definitions = parse_macro_input!(tokens as gen_impl::parser::ParseDefinitions);
let mut definitions = FxHashMap::default(); let mut definitions = FxHashMap::default();
let mut special_definitions = FxHashMap::default();
let types = OpcodeDefinitions::get_enum_types(&parse_definitions.definitions); let types = OpcodeDefinitions::get_enum_types(&parse_definitions.definitions);
let enum_types_tokens = emit_enum_types(types, parse_definitions.additional_enums); let enum_types_tokens = emit_enum_types(types, parse_definitions.additional_enums);
for definition in parse_definitions.definitions.into_iter() { 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 let definitions = definitions
.into_iter() .into_iter()
@ -363,9 +379,12 @@ pub fn derive_parser(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream
}) })
.collect::<FxHashMap<_, _>>(); .collect::<FxHashMap<_, _>>();
let mut token_enum = parse_definitions.token_type; let mut token_enum = parse_definitions.token_type;
let (all_opcode, all_modifier) = let (all_opcode, all_modifier) = write_definitions_into_tokens(
write_definitions_into_tokens(&definitions, &mut token_enum.variants); &definitions,
let token_impl = emit_parse_function(&token_enum.ident, &definitions, all_opcode, all_modifier); 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! { let tokens = quote! {
#enum_types_tokens #enum_types_tokens
@ -422,6 +441,7 @@ fn emit_enum_types(
fn emit_parse_function( fn emit_parse_function(
type_name: &Ident, type_name: &Ident,
defs: &FxHashMap<Ident, OpcodeDefinitions>, defs: &FxHashMap<Ident, OpcodeDefinitions>,
special_defs: &FxHashMap<Ident, proc_macro2::Group>,
all_opcode: Vec<&Ident>, all_opcode: Vec<&Ident>,
all_modifier: FxHashSet<&parser::DotModifier>, all_modifier: FxHashSet<&parser::DotModifier>,
) -> TokenStream { ) -> TokenStream {
@ -433,7 +453,7 @@ fn emit_parse_function(
let mut fn_name = opcode.to_string(); let mut fn_name = opcode.to_string();
write!(&mut fn_name, "_{}", idx).ok(); write!(&mut fn_name, "_{}", idx).ok();
let fn_name = Ident::new(&fn_name, Span::call_site()); 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(); let args = def.function_arguments_declarations();
quote! { quote! {
fn #fn_name<'input>(state: &mut PtxParserState, #(#args),* ) -> Instruction<ParsedOperandStr<'input>> #code_block 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); .to_tokens(&mut result);
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 opcodes = all_opcode.into_iter().map(|op_ident| {
let op = op_ident.to_string(); let op = op_ident.to_string();
let variant = Ident::new(&capitalize(&op), op_ident.span()); let variant = Ident::new(&capitalize(&op), op_ident.span());
@ -749,7 +774,7 @@ fn emit_definition_parser(
}; };
let pre_pipe = if arg.pre_pipe { let pre_pipe = if arg.pre_pipe {
quote! { quote! {
any.verify(|t| *t == #token_type::Or).void() any.verify(|t| *t == #token_type::Pipe).void()
} }
} else { } else {
quote! { quote! {
@ -845,6 +870,7 @@ fn emit_definition_parser(
fn write_definitions_into_tokens<'a>( fn write_definitions_into_tokens<'a>(
defs: &'a FxHashMap<Ident, OpcodeDefinitions>, defs: &'a FxHashMap<Ident, OpcodeDefinitions>,
special_definitions: impl Iterator<Item = &'a Ident>,
variants: &mut Punctuated<Variant, Token![,]>, variants: &mut Punctuated<Variant, Token![,]>,
) -> (Vec<&'a Ident>, FxHashSet<&'a parser::DotModifier>) { ) -> (Vec<&'a Ident>, FxHashSet<&'a parser::DotModifier>) {
let mut all_opcodes = Vec::new(); 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() { for modifier in all_modifiers.iter() {
let modifier_as_string = modifier.to_string(); let modifier_as_string = modifier.to_string();
let variant_name = modifier.dot_capitalized(); let variant_name = modifier.dot_capitalized();

View file

@ -1,8 +1,8 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::{ use syn::{
braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, Token, Type, TypeParam, braced, parse::Parse, punctuated::Punctuated, token, Expr, Ident, PathSegment, Token, Type,
Visibility, TypeParam, Visibility,
}; };
pub mod parser; pub mod parser;
@ -18,7 +18,7 @@ pub struct GenerateInstructionType {
impl GenerateInstructionType { impl GenerateInstructionType {
pub fn emit_arg_types(&self, tokens: &mut TokenStream) { pub fn emit_arg_types(&self, tokens: &mut TokenStream) {
for v in self.variants.iter() { 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 struct InstructionVariant {
pub name: Ident, pub name: Ident,
pub type_: Option<Expr>, pub type_: Option<Option<Expr>>,
pub space: Option<Expr>, pub space: Option<Expr>,
pub data: Option<Type>, pub data: Option<Type>,
pub arguments: Option<InstructionArguments>, pub arguments: Option<InstructionArguments>,
@ -225,7 +225,7 @@ impl InstructionVariant {
&self, &self,
enum_: &Ident, enum_: &Ident,
tokens: &mut TokenStream, 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 name = &self.name;
let arguments = match &self.arguments { let arguments = match &self.arguments {
@ -238,9 +238,10 @@ impl InstructionVariant {
} }
Some(args) => args, Some(args) => args,
}; };
let data = &self.data.as_ref().map(|_| quote! { data,});
let arg_calls = fn_(arguments, &self.type_, &self.space); let arg_calls = fn_(arguments, &self.type_, &self.space);
quote! { quote! {
#enum_ :: #name { arguments, data } => { #enum_ :: #name { #data arguments } => {
#arg_calls #arg_calls
} }
} }
@ -269,19 +270,14 @@ impl InstructionVariant {
.to_tokens(tokens); .to_tokens(tokens);
} }
fn emit_type( fn emit_type(&self, vis: &Option<Visibility>, tokens: &mut TokenStream) {
&self,
vis: &Option<Visibility>,
type_parameters: &Punctuated<TypeParam, Token![,]>,
tokens: &mut TokenStream,
) {
let arguments = match self.arguments { let arguments = match self.arguments {
Some(ref a) => a, Some(ref a) => a,
None => return, None => return,
}; };
let name = self.args_name(); let name = self.args_name();
let type_parameters = if arguments.generic.is_some() { let type_parameters = if arguments.generic.is_some() {
Some(quote! { <#type_parameters> }) Some(quote! { <T> })
} else { } else {
None None
}; };
@ -324,7 +320,7 @@ impl Parse for InstructionVariant {
} }
enum VariantProperty { enum VariantProperty {
Type(Expr), Type(Option<Expr>),
Space(Expr), Space(Expr),
Data(Type), Data(Type),
Arguments(InstructionArguments), Arguments(InstructionArguments),
@ -336,7 +332,12 @@ impl VariantProperty {
Ok(if lookahead.peek(Token![type]) { Ok(if lookahead.peek(Token![type]) {
input.parse::<Token![type]>()?; input.parse::<Token![type]>()?;
input.parse::<Token![:]>()?; 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) { } else if lookahead.peek(Ident) {
let key = input.parse::<Ident>()?; let key = input.parse::<Ident>()?;
match &*key.to_string() { match &*key.to_string() {
@ -352,7 +353,7 @@ impl VariantProperty {
let generics = if input.peek(Token![<]) { let generics = if input.peek(Token![<]) {
input.parse::<Token![<]>()?; input.parse::<Token![<]>()?;
let gen_params = let gen_params =
Punctuated::<TypeParam, Token![,]>::parse_separated_nonempty(input)?; Punctuated::<PathSegment, syn::token::PathSep>::parse_separated_nonempty(input)?;
input.parse::<Token![>]>()?; input.parse::<Token![>]>()?;
Some(gen_params) Some(gen_params)
} else { } else {
@ -380,13 +381,13 @@ impl VariantProperty {
} }
pub struct InstructionArguments { pub struct InstructionArguments {
pub generic: Option<Punctuated<TypeParam, Token![,]>>, pub generic: Option<Punctuated<PathSegment, syn::token::PathSep>>,
pub fields: Punctuated<ArgumentField, Token![,]>, pub fields: Punctuated<ArgumentField, Token![,]>,
} }
impl InstructionArguments { impl InstructionArguments {
pub fn parse( pub fn parse(
generic: Option<Punctuated<TypeParam, Token![,]>>, generic: Option<Punctuated<PathSegment, syn::token::PathSep>>,
input: syn::parse::ParseStream, input: syn::parse::ParseStream,
) -> syn::Result<Self> { ) -> syn::Result<Self> {
let fields = Punctuated::<ArgumentField, Token![,]>::parse_terminated_with( let fields = Punctuated::<ArgumentField, Token![,]>::parse_terminated_with(
@ -396,13 +397,17 @@ impl InstructionArguments {
Ok(Self { generic, fields }) 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) self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit)
} }
fn emit_visit_mut( fn emit_visit_mut(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &Option<Expr>, parent_space: &Option<Expr>,
) -> TokenStream { ) -> TokenStream {
self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_mut) self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_mut)
@ -410,7 +415,7 @@ impl InstructionArguments {
fn emit_visit_map( fn emit_visit_map(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &Option<Expr>, parent_space: &Option<Expr>,
) -> TokenStream { ) -> TokenStream {
self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_map) self.emit_visit_impl(parent_type, parent_space, ArgumentField::emit_visit_map)
@ -418,14 +423,19 @@ impl InstructionArguments {
fn emit_visit_impl( fn emit_visit_impl(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &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 { ) -> TokenStream {
let is_ident = if let Some(ref generic) = self.generic {
generic.len() > 1
} else {
false
};
let field_calls = self let field_calls = self
.fields .fields
.iter() .iter()
.map(|f| fn_(f, parent_type, parent_space)); .map(|f| fn_(f, parent_type, parent_space, is_ident));
quote! { quote! {
#(#field_calls)* #(#field_calls)*
} }
@ -487,25 +497,37 @@ impl ArgumentField {
input.parse::<Type>() input.parse::<Type>()
} }
fn emit_visit(&self, parent_type: &Option<Expr>, parent_space: &Option<Expr>) -> TokenStream { fn emit_visit(
self.emit_visit_impl(parent_type, parent_space, false) &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( fn emit_visit_mut(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &Option<Expr>, parent_space: &Option<Expr>,
is_ident: bool,
) -> TokenStream { ) -> 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( fn emit_visit_impl(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &Option<Expr>, parent_space: &Option<Expr>,
is_ident: bool,
is_mut: bool, is_mut: bool,
) -> TokenStream { ) -> 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 let space = self
.space .space
.as_ref() .as_ref()
@ -514,38 +536,72 @@ impl ArgumentField {
.unwrap_or_else(|| quote! { StateSpace::Reg }); .unwrap_or_else(|| quote! { StateSpace::Reg });
let is_dst = self.is_dst; let is_dst = self.is_dst;
let name = &self.name; let name = &self.name;
let (operand_fn, arguments_name) = if is_mut { let type_space = if is_typeless {
( quote! {
quote! { let type_space = None;
VisitOperand::visit_mut }
},
quote! {
&mut arguments.#name
},
)
} else { } else {
( quote! {
quote! { let type_ = #type_;
VisitOperand::visit let space = #space;
}, let type_space = Some((std::borrow::Borrow::<Type>::borrow(&type_), space));
quote! { }
& arguments.#name
},
)
}; };
quote! {{ if is_ident {
let type_ = #type_; if is_mut {
let space = #space; quote! {
#operand_fn(#arguments_name, |x| visitor.visit(x, &type_, space, #is_dst)); {
}} #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( fn emit_visit_map(
&self, &self,
parent_type: &Option<Expr>, parent_type: &Option<Option<Expr>>,
parent_space: &Option<Expr>, parent_space: &Option<Expr>,
is_ident: bool,
) -> TokenStream { ) -> 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 let space = self
.space .space
.as_ref() .as_ref()
@ -554,11 +610,30 @@ impl ArgumentField {
.unwrap_or_else(|| quote! { StateSpace::Reg }); .unwrap_or_else(|| quote! { StateSpace::Reg });
let is_dst = self.is_dst; let is_dst = self.is_dst;
let name = &self.name; let name = &self.name;
quote! { let type_space = if is_typeless {
let #name = { quote! {
let type_space = None;
}
} else {
quote! {
let type_ = #type_; let type_ = #type_;
let space = #space; 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)); 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] #[test]
fn visit_variant_empty() { fn visit_variant_empty() {
let input = quote! { let input = quote! {

View file

@ -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 { impl Parse for CodeBlock {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
input.parse::<Token![=>]>()?; let lookahead = input.lookahead1();
let group = input.parse::<proc_macro2::Group>()?; let (special, code) = if lookahead.peek(Token![<]) {
Ok(Self(group)) 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} } .ss: StateSpace = { .global, .local, .param{::func}, .shared{::cta, ::cluster} }
}; };
let rule = syn::parse2::<super::Rule>(input).unwrap(); 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!( assert_eq!(
"StateSpace", "StateSpace",
rule.type_.unwrap().to_token_stream().to_string() rule.type_.unwrap().to_token_stream().to_string()
@ -791,7 +805,7 @@ mod tests {
.cop: StCacheOperator = { .wb, .cg, .cs, .wt } .cop: StCacheOperator = { .wb, .cg, .cs, .wt }
}; };
let rule = syn::parse2::<super::Rule>(input).unwrap(); 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!( assert_eq!(
"StCacheOperator", "StCacheOperator",
rule.type_.unwrap().to_token_stream().to_string() rule.type_.unwrap().to_token_stream().to_string()
@ -819,4 +833,12 @@ mod tests {
assert!(!a.can_be_negated); assert!(!a.can_be_negated);
assert!(a.unified); assert!(a.unified);
} }
#[test]
fn special_block() {
let input = quote! {
bra <= { bra(stream) }
};
syn::parse2::<super::OpcodeDefinition>(input).unwrap();
}
} }

View file

@ -31,7 +31,7 @@ gen::generate_instruction_type!(
} }
}, },
Add { Add {
type: { data.type_().into() }, type: { Type::from(data.type_()) },
data: ArithDetails, data: ArithDetails,
arguments<T>: { arguments<T>: {
dst: T, dst: T,
@ -51,12 +51,12 @@ gen::generate_instruction_type!(
} }
}, },
Mul { Mul {
type: { data.type_().into() }, type: { Type::from(data.type_()) },
data: MulDetails, data: MulDetails,
arguments<T>: { arguments<T>: {
dst: { dst: {
repr: T, repr: T,
type: { data.dst_type().into() }, type: { Type::from(data.dst_type()) },
}, },
src1: T, src1: T,
src2: T, src2: T,
@ -67,19 +67,19 @@ gen::generate_instruction_type!(
arguments<T>: { arguments<T>: {
dst1: { dst1: {
repr: T, repr: T,
type: ScalarType::Pred.into() type: Type::from(ScalarType::Pred)
}, },
dst2: { dst2: {
repr: Option<T>, repr: Option<T>,
type: ScalarType::Pred.into() type: Type::from(ScalarType::Pred)
}, },
src1: { src1: {
repr: T, repr: T,
type: data.type_.into(), type: Type::from(data.type_),
}, },
src2: { src2: {
repr: T, repr: T,
type: data.type_.into(), type: Type::from(data.type_),
} }
} }
}, },
@ -88,26 +88,58 @@ gen::generate_instruction_type!(
arguments<T>: { arguments<T>: {
dst1: { dst1: {
repr: T, repr: T,
type: ScalarType::Pred.into() type: Type::from(ScalarType::Pred)
}, },
dst2: { dst2: {
repr: Option<T>, repr: Option<T>,
type: ScalarType::Pred.into() type: Type::from(ScalarType::Pred)
}, },
src1: { src1: {
repr: T, repr: T,
type: data.base.type_.into(), type: Type::from(data.base.type_),
}, },
src2: { src2: {
repr: T, repr: T,
type: data.base.type_.into(), type: Type::from(data.base.type_),
}, },
src3: { src3: {
repr: T, 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 { Ret {
data: RetData data: RetData
}, },
@ -115,21 +147,26 @@ gen::generate_instruction_type!(
} }
); );
pub trait Visitor<T> { pub trait Visitor<T: Operand> {
fn visit(&mut self, args: &T, type_: &Type, space: StateSpace, is_dst: bool); 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> { pub trait VisitorMut<T: Operand> {
fn visit(&mut self, args: &mut T, type_: &Type, space: StateSpace, is_dst: bool); 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> { pub trait VisitorMap<From: Operand, To: Operand> {
fn visit(&mut self, args: From, type_: &Type, space: StateSpace, is_dst: bool) -> To; 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 { trait VisitOperand {
type Operand; type Operand: Operand;
#[allow(unused)] // Used by generated code
fn visit(&self, fn_: impl FnOnce(&Self::Operand)); 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)); 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 { trait MapOperand: Sized {
type Input; type Input;
type Output<U>; type Output<U>;
#[allow(unused)] // Used by generated code
fn map<U>(self, fn_: impl FnOnce(Self::Input) -> U) -> Self::Output<U>; fn map<U>(self, fn_: impl FnOnce(Self::Input) -> U) -> Self::Output<U>;
} }
@ -289,12 +327,12 @@ pub enum ParsedOperand<Ident> {
VecPack(Vec<Ident>), VecPack(Vec<Ident>),
} }
impl<Ident> Operand for ParsedOperand<Ident> { impl<Ident: Copy> Operand for ParsedOperand<Ident> {
type Ident = Ident; type Ident = Ident;
} }
pub trait Operand { pub trait Operand {
type Ident; type Ident: Copy;
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -447,6 +485,7 @@ pub enum MulDetails {
} }
impl MulDetails { impl MulDetails {
#[allow(unused)] // Used by generated code
fn type_(&self) -> ScalarType { fn type_(&self) -> ScalarType {
match self { match self {
MulDetails::Integer { type_, .. } => *type_, MulDetails::Integer { type_, .. } => *type_,
@ -454,6 +493,7 @@ impl MulDetails {
} }
} }
#[allow(unused)] // Used by generated code
fn dst_type(&self) -> ScalarType { fn dst_type(&self) -> ScalarType {
match self { match self {
MulDetails::Integer { MulDetails::Integer {
@ -521,7 +561,7 @@ impl SetpData {
pub struct SetpBoolData { pub struct SetpBoolData {
pub base: SetpData, pub base: SetpData,
pub bool_op: SetpBoolPostOp, pub bool_op: SetpBoolPostOp,
pub negate_src3: bool pub negate_src3: bool,
} }
#[derive(PartialEq, Eq, Copy, Clone)] #[derive(PartialEq, Eq, Copy, Clone)]

View file

@ -623,7 +623,7 @@ fn predicated_instruction<'a, 'input>(
} }
fn pred_at<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<ast::PredAt<&'input str>> { 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 { .map(|(_, not, label)| ast::PredAt {
not: not.is_some(), not: not.is_some(),
label, 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: // Modifiers are turned into arguments to the blocks, with type:
// * If it is an alternative: // * If it is an alternative:
// * If it is mandatory then its type is Foo (as defined by the relevant rule) // * If it is mandatory then its type is Foo (as defined by the relevant rule)
@ -919,9 +934,9 @@ derive_parser!(
#[regex(r#""[^"]*""#)] #[regex(r#""[^"]*""#)]
String, String,
#[token("|")] #[token("|")]
Or, Pipe,
#[token("!")] #[token("!")]
Not, Exclamation,
#[token("(")] #[token("(")]
LParen, LParen,
#[token(")")] #[token(")")]
@ -1461,6 +1476,36 @@ derive_parser!(
.f32, .f64, .f32, .f64,
.f16, .f16x2, .bf16, .bf16x2 }; .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 // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#control-flow-instructions-ret
ret{.uni} => { ret{.uni} => {
Instruction::Ret { data: RetData { uniform: uni } } Instruction::Ret { data: RetData { uniform: uni } }