SPIR-V parser generator is complete
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 2 Nov 2018 06:44:34 +0000 (23:44 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 2 Nov 2018 06:44:34 +0000 (23:44 -0700)
spirv-parser-generator/src/generate.rs
spirv-parser/src/lib.rs
spirv-parser/test_inputs/test2.spv [new file with mode: 0644]
spirv-parser/test_inputs/test3.spv [new file with mode: 0644]

index c456c3c7c00ba54fba33fc5f7b2564575fe326ac..dd836a3542530e45be7b1f21a3cfab636cf3c48d 100644 (file)
@@ -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(&parameter.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);
index 198ee4d2f55daba8291797c8f7df419c9b714592..70b01f20a825bba99c5064f48928e3c18786008e 100644 (file)
@@ -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 (file)
index 0000000..5791397
Binary files /dev/null and b/spirv-parser/test_inputs/test2.spv differ
diff --git a/spirv-parser/test_inputs/test3.spv b/spirv-parser/test_inputs/test3.spv
new file mode 100644 (file)
index 0000000..22a8ade
Binary files /dev/null and b/spirv-parser/test_inputs/test3.spv differ