From 78839db881055783a824bc16b967587e9f4bec0a Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 1 Nov 2018 23:44:34 -0700 Subject: [PATCH] SPIR-V parser generator is complete --- spirv-parser-generator/src/generate.rs | 119 ++++++++++++++++++++----- spirv-parser/src/lib.rs | 98 ++++++++++++++++++++ spirv-parser/test_inputs/test2.spv | Bin 0 -> 176 bytes spirv-parser/test_inputs/test3.spv | Bin 0 -> 792 bytes 4 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 spirv-parser/test_inputs/test2.spv create mode 100644 spirv-parser/test_inputs/test3.spv diff --git a/spirv-parser-generator/src/generate.rs b/spirv-parser-generator/src/generate.rs index c456c3c..dd836a3 100644 --- a/spirv-parser-generator/src/generate.rs +++ b/spirv-parser-generator/src/generate.rs @@ -432,6 +432,7 @@ pub(crate) fn generate( let mut enumerant_member_names = Vec::new(); let mut enumerant_items = Vec::new(); let mut enumerant_parse_operations = Vec::new(); + let mut enumerant_display_mask_operations = Vec::new(); let mut enumerant_display_operations = Vec::new(); let mut none_name = "None"; for enumerant in enumerants { @@ -439,6 +440,7 @@ pub(crate) fn generate( none_name = enumerant.enumerant.as_ref(); continue; } + let enumerant_name = &enumerant.enumerant; let member_name = new_id(&enumerant.enumerant, SnakeCase); let member_name = &member_name; enumerant_member_names.push(member_name.clone()); @@ -451,40 +453,60 @@ pub(crate) fn generate( pub struct #type_name; }); enumerant_parse_operation = quote!{(Some(#type_name), words)}; - enumerant_display_operations.push(quote!{ - if let Some(#type_name) = &self.#member_name { - unimplemented!(); + enumerant_display_mask_operations.push(quote!{ + if self.#member_name.is_some() { + if any_members { + write!(f, "|{}", #enumerant_name)?; + } else { + write!(f, " {}", #enumerant_name)?; + any_members = true; + } } }); + enumerant_display_operations.push(quote!{}); } else { - let mut enumerant_member_declarations = Vec::new(); - let mut enumerant_member_names = Vec::new(); + let mut enumerant_parameter_declarations = Vec::new(); + let mut enumerant_parameter_names = Vec::new(); let mut parse_enumerant_members = Vec::new(); + let mut display_enumerant_members = Vec::new(); for (index, parameter) in enumerant.parameters.iter().enumerate() { let name = new_id(format!("parameter_{}", index), SnakeCase); let kind = new_id(¶meter.kind, CamelCase); - enumerant_member_declarations.push(quote!{ + enumerant_parameter_declarations.push(quote!{ pub #kind, }); - enumerant_member_names.push(quote!{ + enumerant_parameter_names.push(quote!{ #name, }); parse_enumerant_members.push(quote!{ let (#name, words) = #kind::spirv_parse(words, parse_state)?; }); + display_enumerant_members.push(quote!{ + #name.spirv_display(f)?; + }); } enumerant_items.push(quote!{ #[derive(Clone, Debug, Default)] - pub struct #type_name(#(#enumerant_member_declarations)*); + pub struct #type_name(#(#enumerant_parameter_declarations)*); }); - let enumerant_member_names = &enumerant_member_names; + let enumerant_parameter_names = &enumerant_parameter_names; enumerant_parse_operation = quote!{ #(#parse_enumerant_members)* - (Some(#type_name(#(#enumerant_member_names)*)), words) + (Some(#type_name(#(#enumerant_parameter_names)*)), words) }; + enumerant_display_mask_operations.push(quote!{ + if self.#member_name.is_some() { + if any_members { + write!(f, "|{}", #enumerant_name)?; + } else { + write!(f, " {}", #enumerant_name)?; + any_members = true; + } + } + }); enumerant_display_operations.push(quote!{ - if let Some(#type_name(#(#enumerant_member_names)*)) = &self.#member_name { - unimplemented!(); + if let Some(#type_name(#(#enumerant_parameter_names)*)) = &self.#member_name { + #(#display_enumerant_members)* } }); }; @@ -543,13 +565,13 @@ pub(crate) fn generate( quote!{ impl SPIRVDisplay for #kind_id { fn spirv_display(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut is_none = true; - #(#enumerant_display_operations)* - if is_none { - write!(f, " {}", #none_name) - } else { - Ok(()) + let mut any_members = false; + #(#enumerant_display_mask_operations)* + if !any_members { + write!(f, " {}", #none_name)?; } + #(#enumerant_display_operations)* + Ok(()) } } } @@ -788,6 +810,7 @@ pub(crate) fn generate( }; instruction_extension_enumerants.push(instruction_extension_enumerant); let mut parse_operations = Vec::new(); + let mut display_operations = Vec::new(); let mut operand_names = Vec::new(); for operand in &instruction.operands { let kind = new_id(&operand.kind, CamelCase); @@ -800,6 +823,9 @@ pub(crate) fn generate( parse_operations.push(quote!{ let (#name, words) = #kind::spirv_parse(words, parse_state)?; }); + display_operations.push(quote!{ + #name.spirv_display(f)?; + }); operand_names.push(name); } let operand_names = &operand_names; @@ -822,13 +848,25 @@ pub(crate) fn generate( } }; instruction_extension_parse_cases.push(instruction_extension_parse_case); + let display_opname = &instruction.opname; let instruction_extension_display_case = quote!{ Instruction::#instruction_enumerant_name { id_result_type, id_result, set, #(#operand_names,)* - } => unimplemented!(), + } => { + write!( + f, + "{}OpExtInst {} {} {}", + InstructionIndentAndResult(Some(*id_result)), + id_result_type, + set, + #display_opname, + )?; + #(#display_operations)* + writeln!(f) + } }; instruction_extension_display_cases.push(instruction_extension_display_case); } @@ -838,6 +876,7 @@ pub(crate) fn generate( let opcode = instruction.opcode; let opname = new_id(remove_initial_op(instruction.opname.as_ref()), CamelCase); let display_opname = instruction.opname.as_ref(); + let display_opname_without_initial_op = remove_initial_op(display_opname); let instruction_parse_case; let instruction_display_case; match &instruction.opname { @@ -1192,8 +1231,34 @@ pub(crate) fn generate( } }; instruction_display_case = quote!{ - Instruction::SpecConstant32 { .. } => unimplemented!(), - Instruction::SpecConstant64 { .. } => unimplemented!(), + Instruction::SpecConstant32 { + id_result_type, + id_result, + value, + } => { + write!( + f, + "{}{}", + InstructionIndentAndResult(Some(*id_result)), + "OpSpecConstant" + )?; + id_result_type.spirv_display(f)?; + writeln!(f, " {:#010X}", value) + } + Instruction::SpecConstant64 { + id_result_type, + id_result, + value, + } => { + write!( + f, + "{}{}", + InstructionIndentAndResult(Some(*id_result)), + "OpSpecConstant" + )?; + id_result_type.spirv_display(f)?; + writeln!(f, " {:#018X}", value) + } }; } ast::InstructionName::OpSpecConstant64 => { @@ -1307,6 +1372,7 @@ pub(crate) fn generate( let opcode = u32::from(opcode); spec_constant_op_instruction_enumerants.push(instruction_enumerant.clone()); let mut parse_operations = Vec::new(); + let mut display_operations = Vec::new(); let mut operand_names = Vec::new(); operand_names.push(new_id("id_result_type", SnakeCase)); operand_names.push(new_id("id_result", SnakeCase)); @@ -1321,6 +1387,9 @@ pub(crate) fn generate( parse_operations.push(quote!{ let (#name, words) = #kind::spirv_parse(words, parse_state)?; }); + display_operations.push(quote!{ + #name.spirv_display(f)?; + }); operand_names.push(name); } if let Some([operand1, operand2]) = instruction.operands.get(..2) { @@ -1351,7 +1420,13 @@ pub(crate) fn generate( instruction_spec_constant_display_cases.push(quote!{ OpSpecConstantOp::#opname { #(#operand_names,)* - } => unimplemented!(), + } => { + write!(f, "{}{}", InstructionIndentAndResult(Some(*id_result)), "OpSpecConstantOp")?; + id_result_type.spirv_display(f)?; + write!(f, " {}", #display_opname_without_initial_op)?; + #(#display_operations)* + writeln!(f) + } }); } instruction_enumerants.push(instruction_enumerant); diff --git a/spirv-parser/src/lib.rs b/spirv-parser/src/lib.rs index 198ee4d..70b01f2 100644 --- a/spirv-parser/src/lib.rs +++ b/spirv-parser/src/lib.rs @@ -110,6 +110,104 @@ mod tests { %38 = OpLabel OpReturn OpFunctionEnd +"#; + println!("Line-by-line:"); + for (a, b) in output.lines().zip(expected.lines()) { + println!("{}\n{}", a, b); + } + assert!(output == expected); + } + + #[test] + fn parse_test2() { + let output = parse_and_dump(include_bytes!("../test_inputs/test2.spv")).unwrap(); + let expected = r#"; SPIR-V +; Version: 1.3 +; Generator: 0x70000 +; Bound: 12 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeFloat 32 + %4 = OpTypeVector %3 4 + %5 = OpTypeFunction %2 + %1 = OpFunction %2 None %5 + %6 = OpLabel + %7 = OpImageSampleImplicitLod %4 %8 %9 Bias|MinLod %10 %11 + OpReturn + OpFunctionEnd +"#; + println!("Line-by-line:"); + for (a, b) in output.lines().zip(expected.lines()) { + println!("{}\n{}", a, b); + } + assert!(output == expected); + } + + #[test] + fn parse_test3() { + let output = parse_and_dump(include_bytes!("../test_inputs/test3.spv")).unwrap(); + let expected = r#"; SPIR-V +; Version: 1.0 +; Generator: 0x80007 +; Bound: 38 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %4 "main" + OpExecutionMode %4 LocalSize 1 1 1 + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "f(" + OpName %10 "g(" + OpName %14 "h(" + OpName %16 "A" + OpName %17 "B" + OpName %19 "C" + OpDecorate %16 SpecId 0 + OpDecorate %17 SpecId 1 + OpDecorate %19 SpecId 2 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %12 = OpTypeFloat 32 + %13 = OpTypeFunction %12 + %16 = OpSpecConstant %6 0x00000000 + %17 = OpSpecConstant %6 0x00000001 + %18 = OpSpecConstantOp %6 IMul %16 %17 + %19 = OpSpecConstant %6 0x00000002 + %20 = OpSpecConstantOp %6 SDiv %18 %19 + %23 = OpSpecConstantOp %6 BitwiseAnd %16 %17 + %24 = OpSpecConstantOp %6 BitwiseXor %23 %19 + %29 = OpConstant %12 0x3F490FDB + %30 = OpTypeVector %12 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %35 = OpFunctionCall %6 %8 + %36 = OpFunctionCall %6 %10 + %37 = OpFunctionCall %12 %14 + OpReturn + OpFunctionEnd + %8 = OpFunction %6 None %7 + %9 = OpLabel + OpReturnValue %20 + OpFunctionEnd + %10 = OpFunction %6 None %7 + %11 = OpLabel + OpReturnValue %24 + OpFunctionEnd + %14 = OpFunction %12 None %13 + %15 = OpLabel + %27 = OpConvertSToF %12 %16 + %28 = OpExtInst %12 %1 Cos %27 + %31 = OpCompositeConstruct %30 %28 %29 + %32 = OpExtInst %12 %1 Length %31 + OpReturnValue %32 + OpFunctionEnd "#; println!("Line-by-line:"); for (a, b) in output.lines().zip(expected.lines()) { diff --git a/spirv-parser/test_inputs/test2.spv b/spirv-parser/test_inputs/test2.spv new file mode 100644 index 0000000000000000000000000000000000000000..5791397085f99f06f5327fcadca0cb1d9c1b5ceb GIT binary patch literal 176 zcmX|(F%E+;5Ck`Nzywebij=gV`~mS3YRVMk5B!=Y6031{_xF7FRECAz4}cL`s?4R)xZ Ifge{hoWGz3RsaA1 literal 0 HcmV?d00001 diff --git a/spirv-parser/test_inputs/test3.spv b/spirv-parser/test_inputs/test3.spv new file mode 100644 index 0000000000000000000000000000000000000000..22a8ade86ccbda7acf237e1fc715ce0fdc931478 GIT binary patch literal 792 zcmYk3OG-mQ5JlTOW1@-q7&U^wCs7fEAQDAKVjKh^1Hlyt;%A@^bP0m{a-fTFBTf|0 ziQSNX+*h}%ZdLUsD|AXBOoUP>hwbpcnxQ}>gi4qi*}?E~*nNJv?)DD$RMbK?5~`_( zB3}rT;Nj~2(L{qf{U%V8kWp8_eiL zJ*w?F2VQ|Xb4ll(oSk&@@He2|T#C2hpCHwz_!6-XU|#($`*B~Z;H!Rq(#Btd8*|Pf zH>mXuT%P@#h;Mlu&(eYWCduD~`!4$S*#f@J54Us#?CBY;ad~Ie#2ahh?~TQDw5)72um$WA1`IdG2*!&ihE(9Imzx%sV^BI{Ocl C^&^%5 literal 0 HcmV?d00001 -- 2.30.2