Skip to content

Commit

Permalink
WIP lift operations
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Jul 18, 2019
1 parent 4fe0937 commit bf57b8c
Show file tree
Hide file tree
Showing 10 changed files with 1,058 additions and 660 deletions.
9 changes: 9 additions & 0 deletions codegen/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ fn main() {
let c = sr::gen_sr_type_creation(&grammar);
fmt_write!(c, path);
}
let (inst_structs, inst_lifts) = sr::gen_sr_structs_and_lifts(&grammar);
{
let path = codegen_src_dir.join("../rspirv/sr/autogen_instruction_lift.rs");
fmt_write!(inst_lifts, path);
}
{
let path = codegen_src_dir.join("../rspirv/sr/autogen_instruction_struct.rs");
fmt_write!(inst_structs, path);
}
{
//TODO: move items into a separate source
let path = codegen_src_dir.join("../rspirv/sr/autogen_instruction.rs");
Expand Down
157 changes: 134 additions & 23 deletions codegen/sr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,22 @@ pub fn gen_sr_decoration(grammar: &structs::Grammar) -> String {
tokens.to_string()
}

pub fn get_operand_type_ident(grammar: &structs::Operand) -> TokenStream {
let ty = if grammar.kind == "IdRef" {
if grammar.name == "'Length'" {
quote! { ConstantToken }
} else {
quote! { TypeToken }
pub fn get_operand_type_ident(operand: &structs::Operand) -> TokenStream {
let ty = if operand.kind == "IdRef" {
match operand.name.trim_matches('\'') {
"Length" => quote! { ConstantToken },
"Entry Point" => quote! { FunctionToken },
"Interface" => quote! { VariableToken },
_ => quote! { TypeToken },
}
} else {
get_operand_type_sr_tokens(&grammar.kind)
get_operand_type_sr_tokens(&operand.kind)
};
if grammar.quantifier.is_empty() {
quote! { #ty }
} else if grammar.quantifier == "?" {
quote! { Option<#ty> }
} else {
quote! { Vec<#ty> }
match operand.quantifier.as_str() {
"" => quote! { #ty },
"?" => quote! { Option<#ty> },
"*" => quote! { Vec<#ty> },
other => panic!("wrong quantifier: {}", other),
}
}

Expand Down Expand Up @@ -280,6 +280,114 @@ pub fn gen_sr_type_creation(grammar: &structs::Grammar) -> String {
tokens.to_string()
}

fn lift_operand_simple(iter: &Ident, operand: &structs::Operand) -> TokenStream {
let kind_ident = Ident::new(&operand.kind, Span::call_site());
match operand.kind.as_str() {
"PairLiteralIntegerIdRef" |
"PairIdRefLiteralInteger" |
"PairIdRefIdRef" => quote! {
},
_ => {
let value = match operand.name.trim_matches('\'') {
"Length" => quote! { self.get_constant(*value) },
"Entry Point" => quote! { self.get_function(*value) },
"Interface" => quote! { self.get_variable(*value) },
_ => quote! { value.clone() },
};
quote! {
match #iter.next() {
Some(&mr::Operand::#kind_ident(ref value)) => Some(#value),
Some(_) => Err(OperandError::Wrong)?,
None => None,
}
}
}
}
}

fn lift_operand_complex(iter: &Ident, operand: &structs::Operand) -> TokenStream {
let value_token = lift_operand_simple(iter, operand);
match operand.quantifier.as_str() {
"" => quote! {
(#value_token).ok_or(OperandError::Missing)?
},
"?" => value_token,
"*" => quote! {
{
let mut vec = Vec::new();
while let Some(value) = #value_token {
vec.push(value);
}
vec
}
},
other => panic!("wrong quantifier: {}", other),
}
}

pub fn gen_sr_structs_and_lifts(grammar: &structs::Grammar) -> (String, String) {
let mut structs = Vec::new();
let mut lifts = Vec::new();
for inst in grammar.instructions.iter() {
if inst.class != "ModeSetting" {
continue
}
// Get the token for its enumerant
let struct_name = Ident::new(&inst.opname[2..], Span::call_site());
let ident_operands = Ident::new("operands", Span::call_site());
let mut declarations = Vec::new();
let mut definitions = Vec::new();

for operand in inst.operands.iter() {
if operand.kind.starts_with("IdResult") {
continue
}
let field_name = get_operand_name_sr_tokens(operand);
let field_type = get_operand_type_ident(operand);
let constructor = lift_operand_complex(&ident_operands, operand);

declarations.push(quote! {
pub #field_name: #field_type,
});
definitions.push(quote! {
#field_name : #constructor,
});
}

let opcode = inst.opcode;
let method_name = Ident::new(
&format!("lift_{}", snake_casify(&inst.opname[2..])),
Span::call_site(),
);

structs.push(quote! {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct #struct_name {
#( #declarations )*
}
});
lifts.push(quote! {
impl Context {
pub fn #method_name(
&mut self, raw: &mr::Instruction
) -> Result<structs::#struct_name, LiftError> {
if raw.class.opcode as u32 != #opcode {
return Err(LiftError::OpCode)
}
let mut #ident_operands = raw.operands.iter();
Ok(structs::#struct_name {
#( #definitions )*
})
}
}
});
};

let structs = quote!( #( #structs )* );
let lifts = quote!( #( #lifts )* );
(structs.to_string(), lifts.to_string())
}

pub fn gen_sr_instruction(grammar: &structs::Grammar) -> String {
let mut structs = Vec::new();
let mut terminators = Vec::new();
Expand All @@ -303,26 +411,29 @@ pub fn gen_sr_instruction(grammar: &structs::Grammar) -> String {
None
} else {
let field_name = get_operand_name_sr_tokens(operand);
let field_type = get_operand_type_sr_tokens(&operand.kind);
if operand.quantifier == "" {
Some(quote! { #field_name : #field_type })
} else if operand.quantifier == "?" {
Some(quote! { #field_name : Option<#field_type> })
} else {
Some(quote! { #field_name : Vec<#field_type> })
}
let field_type = get_operand_type_ident(operand);
Some(quote! { #field_name : #field_type })
}
}).collect();

match inst.class.as_str() {
"ModeSetting" |
"ModeSetting" => {
// skip
}
"ExtensionDecl" |
"FunctionStruct" => {
// Create a standalone struct
let declarations: Vec<_> = params
.iter()
.map(|param| quote! {
pub #param,
})
.collect();

structs.push(quote! {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct #name {
#( #params ),*
#( #declarations )*
}
})
}
Expand Down
Loading

0 comments on commit bf57b8c

Please sign in to comment.