Skip to content

Commit

Permalink
Basic lift operations, refactored Context
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Jul 19, 2019
1 parent 8e49446 commit 2b2305e
Show file tree
Hide file tree
Showing 18 changed files with 1,317 additions and 1,053 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
202 changes: 152 additions & 50 deletions codegen/sr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,19 @@ use proc_macro2::{Ident, Span, TokenStream};
/// Returns the corresponding Rust type used in structured representation
/// for the given operand kind in the SPIR-V JSON grammar.
pub fn get_operand_type_sr_tokens(kind: &str) -> TokenStream {
if kind.starts_with("Id") {
quote! { spirv::Word }
} else if kind == "LiteralInteger" || kind == "LiteralExtInstInteger" {
quote! { u32 }
} else if kind == "LiteralSpecConstantOpInteger" {
quote! { spirv::Op }
} else if kind == "LiteralContextDependentNumber" {
panic!("this kind is not expected to be handled here")
} else if kind == "LiteralString" {
quote! { String }
} else if kind == "PairLiteralIntegerIdRef" {
quote! { (u32, spirv::Word) }
} else if kind == "PairIdRefLiteralInteger" {
quote! { (spirv::Word, u32) }
} else if kind == "PairIdRefIdRef" {
quote! { (spirv::Word, spirv::Word) }
} else {
let kind = Ident::new(kind, Span::call_site());
quote! { spirv::#kind }
match kind {
"IdMemorySemantics" | "IdScope" | "IdRef" | "IdResult" => quote! { spirv::Word },
"LiteralInteger" | "LiteralExtInstInteger" => quote! { u32 },
"LiteralSpecConstantOpInteger" => quote! { spirv::Op },
"LiteralContextDependentNumber" => panic!("this kind is not expected to be handled here"),
"LiteralString" => quote! { String },
"PairLiteralIntegerIdRef" => quote! { (u32, spirv::Word) },
"PairIdRefLiteralInteger" => quote! { (spirv::Word, u32) },
"PairIdRefIdRef" => quote! { (spirv::Word, spirv::Word) },
_ => {
let kind = Ident::new(kind, Span::call_site());
quote! { spirv::#kind }
}
}
}

Expand Down Expand Up @@ -101,22 +95,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! { Token<Constant> },
"Entry Point" => quote! { Token<Function> },
"Interface" => quote! { Token<Variable> },
_ => quote! { Token<Type> },
}
} 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 @@ -260,14 +254,11 @@ pub fn gen_sr_type_creation(grammar: &structs::Grammar) -> String {
quote! { {#( #init_list ),*} }
};
quote! {
pub fn #func_name #param_list -> TypeToken {
let t = Type { ty: TypeEnum::#symbol #init_list, decorations: Vec::new() };
if let Some(index) = self.types.iter().position(|x| *x == t) {
TypeToken::new(index)
} else {
self.types.push(t);
TypeToken::new(self.types.len() - 1)
}
pub fn #func_name #param_list -> Token<Type> {
self.types.fetch_or_append(Type {
ty: TypeEnum::#symbol #init_list,
decorations: Vec::new(),
})
}
}
})
Expand All @@ -280,6 +271,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! { Token::new(*value) },
"Entry Point" => quote! { Token::new(*value) },
"Interface" => quote! { Token::new(*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 +402,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
1 change: 1 addition & 0 deletions rspirv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ travis-ci = { repository = "gfx-rs/rspirv" }
num = "0.2"
derive_more = "0.7"
clippy = { version = "0.0", optional = true }
fxhash = "0.2"

[dependencies.spirv_headers]
version = "1.3"
Expand Down
1 change: 1 addition & 0 deletions rspirv/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ extern crate assert_matches;
#[macro_use]
extern crate derive_more;
extern crate num;
extern crate fxhash;
pub extern crate spirv_headers as spirv;

pub mod binary;
Expand Down
2 changes: 1 addition & 1 deletion rspirv/mr/constructs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub struct Module {
}

/// Data representation of a SPIR-V module header.
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleHeader {
pub magic_number: Word,
pub version: Word,
Expand Down
Loading

0 comments on commit 2b2305e

Please sign in to comment.