1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
7 use std::collections::HashMap;
9 use std::io::{self, Read, Write};
10 use std::process::{Child, Command, ExitStatus, Stdio};
12 use util::{self, NameFormat::*};
20 WhichError(which::Error),
21 RustFmtFailed(ExitStatus),
24 impl fmt::Display for FormatError {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27 FormatError::IOError(v) => fmt::Display::fmt(v, f),
28 FormatError::WhichError(v) => fmt::Display::fmt(v, f),
29 FormatError::RustFmtFailed(v) => write!(f, "rustfmt failed: {:?}", v),
34 impl From<which::Error> for FormatError {
35 fn from(v: which::Error) -> Self {
36 FormatError::WhichError(v)
40 impl From<io::Error> for FormatError {
41 fn from(v: io::Error) -> Self {
42 FormatError::IOError(v)
46 fn format_source<'a>(options: &Options, source: &'a str) -> Result<Cow<'a, str>, FormatError> {
47 if !options.run_rustfmt {
48 return Ok(Cow::Borrowed(source));
50 let rustfmt_path = match options.rustfmt_path.clone() {
52 None => which::which("rustfmt")?,
54 let mut command = Command::new(rustfmt_path)
55 .stdin(Stdio::piped())
56 .stdout(Stdio::piped())
58 let stdin = command.stdin.take().unwrap();
59 let reader_thread = thread::spawn(move || -> io::Result<(String, Child)> {
60 let mut output = String::new();
61 command.stdout.take().unwrap().read_to_string(&mut output)?;
64 { stdin }.write_all(source.as_bytes())?;
65 let (output, mut command) = reader_thread.join().unwrap()?;
66 let exit_status = command.wait()?;
67 if exit_status.success() {
68 Ok(Cow::Owned(output))
70 Err(FormatError::RustFmtFailed(exit_status))
74 fn remove_initial_op(name: &str) -> &str {
75 const INITIAL_OP: &str = "Op";
76 assert!(name.starts_with(INITIAL_OP));
77 &name[INITIAL_OP.len()..]
80 fn new_id<T: AsRef<str>>(name: T, name_format: util::NameFormat) -> proc_macro2::Ident {
81 proc_macro2::Ident::new(
83 .name_from_words(util::WordIterator::new(name.as_ref()))
85 proc_macro2::Span::call_site(),
89 fn new_enumerant_id<T1: AsRef<str>, T2: AsRef<str>>(
92 ) -> proc_macro2::Ident {
93 let enumerant_name_words = util::WordIterator::new(enumerant_name.as_ref());
94 let enumerant_name_first_word = enumerant_name_words.clone().next();
95 let name = if enumerant_name_first_word
98 .and_then(Iterator::next)
99 .filter(char::is_ascii_digit)
104 util::WordIterator::new(enum_name.as_ref()).chain(enumerant_name_words),
108 CamelCase.name_from_words(enumerant_name_words).unwrap()
110 proc_macro2::Ident::new(&name, proc_macro2::Span::call_site())
113 fn new_combined_id<I: IntoIterator>(names: I, name_format: util::NameFormat) -> proc_macro2::Ident
117 let names: Vec<I::Item> = names.into_iter().collect();
118 proc_macro2::Ident::new(
124 .flat_map(util::WordIterator::new),
127 proc_macro2::Span::call_site(),
131 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
132 pub(crate) fn generate(
133 core_grammar: ast::CoreGrammar,
134 parsed_extension_instruction_sets: HashMap<
135 super::ExtensionInstructionSet,
136 ast::ExtensionInstructionSet,
139 ) -> Result<String, Error> {
140 let mut out = Vec::new();
141 let ast::CoreGrammar {
142 copyright: core_grammar_copyright,
146 revision: core_revision,
147 instructions: core_instructions,
150 writeln!(&mut out, "// automatically generated file")?;
151 writeln!(&mut out, "//")?;
152 for i in &core_grammar_copyright {
153 assert_eq!(i.find('\r'), None);
154 assert_eq!(i.find('\n'), None);
156 writeln!(&mut out, "//");
158 writeln!(&mut out, "// {}", i);
169 use std::str::Utf8Error;
170 use std::string::FromUtf8Error;
172 trait SPIRVParse: Sized {
173 fn spirv_parse<'a>(words: &'a [u32], parse_state: &mut ParseState)
174 -> Result<(Self, &'a [u32])>;
177 impl<T: SPIRVParse> SPIRVParse for Option<T> {
180 parse_state: &mut ParseState,
181 ) -> Result<(Self, &'a [u32])> {
182 if words.is_empty() {
185 let (value, words) = T::spirv_parse(words, parse_state)?;
186 Ok((Some(value), words))
191 impl<T: SPIRVParse> SPIRVParse for Vec<T> {
193 mut words: &'a [u32],
194 parse_state: &mut ParseState,
195 ) -> Result<(Self, &'a [u32])> {
196 let mut retval = Vec::new();
197 while !words.is_empty() {
198 let result = T::spirv_parse(words, parse_state)?;
200 retval.push(result.0);
206 impl<A: SPIRVParse, B: SPIRVParse> SPIRVParse for (A, B) {
209 parse_state: &mut ParseState,
210 ) -> Result<(Self, &'a [u32])> {
211 let (a, words) = A::spirv_parse(words, parse_state)?;
212 let (b, words) = B::spirv_parse(words, parse_state)?;
217 const BYTES_PER_WORD: usize = 4;
219 struct ByteIterator<'a> {
220 current_word: [u8; BYTES_PER_WORD],
221 current_word_index: usize,
225 impl<'a> ByteIterator<'a> {
226 fn new(words: &'a [u32]) -> Self {
228 current_word: [0; BYTES_PER_WORD],
229 current_word_index: BYTES_PER_WORD,
233 fn take_unread_words(&mut self) -> &'a [u32] {
234 mem::replace(&mut self.words, &[])
238 impl<'a> Iterator for ByteIterator<'a> {
240 fn next(&mut self) -> Option<u8> {
241 if self.current_word_index >= BYTES_PER_WORD {
242 let (¤t_word, words) = self.words.split_first()?;
244 self.current_word = unsafe { mem::transmute(current_word.to_le()) };
245 self.current_word_index = 0;
247 let byte = self.current_word[self.current_word_index];
248 self.current_word_index += 1;
253 impl SPIRVParse for String {
256 _parse_state: &mut ParseState,
257 ) -> Result<(Self, &'a [u32])> {
258 let mut byte_count_excluding_null_terminator = None;
259 for (index, byte) in ByteIterator::new(words).enumerate() {
261 byte_count_excluding_null_terminator = Some(index);
265 let byte_count_excluding_null_terminator =
266 byte_count_excluding_null_terminator.ok_or(Error::InstructionPrematurelyEnded)?;
267 let mut bytes = Vec::with_capacity(byte_count_excluding_null_terminator);
268 let mut byte_iter = ByteIterator::new(words);
269 for _ in 0..byte_count_excluding_null_terminator {
270 let byte = byte_iter.next().unwrap();
273 let _null_terminator = byte_iter.next().unwrap();
274 let words = byte_iter.take_unread_words();
277 return Err(Error::InvalidStringTermination);
280 assert_eq!(bytes.len(), byte_count_excluding_null_terminator);
281 Ok((String::from_utf8(bytes)?, words))
285 impl SPIRVParse for u32 {
288 _parse_state: &mut ParseState,
289 ) -> Result<(Self, &'a [u32])> {
290 let (&value, words) = words
292 .ok_or(Error::InstructionPrematurelyEnded)?;
297 impl SPIRVParse for u64 {
300 _parse_state: &mut ParseState,
301 ) -> Result<(Self, &'a [u32])> {
302 let (&low, words) = words
304 .ok_or(Error::InstructionPrematurelyEnded)?;
305 let (&high, words) = words
307 .ok_or(Error::InstructionPrematurelyEnded)?;
308 Ok((((high as u64) << 32) | low as u64, words))
312 impl SPIRVParse for IdRef {
315 parse_state: &mut ParseState,
316 ) -> Result<(Self, &'a [u32])> {
317 let (value, words) = u32::spirv_parse(words, parse_state)?;
318 if value == 0 || value as usize >= parse_state.id_states.len() {
319 Err(Error::IdOutOfBounds(value))
321 Ok((IdRef(value), words))
331 pub const MAGIC_NUMBER: u32 = #magic_number;
332 pub const MAJOR_VERSION: u32 = #major_version;
333 pub const MINOR_VERSION: u32 = #minor_version;
334 pub const REVISION: u32 = #core_revision;
337 for operand_kind in &operand_kinds {
339 ast::OperandKind::BitEnum { kind, enumerants } => {
340 let kind_id = new_id(kind, CamelCase);
341 let mut enumerant_members = Vec::new();
342 let mut enumerant_member_names = Vec::new();
343 let mut enumerant_items = Vec::new();
344 let mut enumerant_parse_operations = Vec::new();
345 for enumerant in enumerants {
346 if enumerant.value.0 == 0 {
349 let member_name = new_id(&enumerant.enumerant, SnakeCase);
350 enumerant_member_names.push(member_name.clone());
352 new_combined_id(&[kind.as_ref(), &enumerant.enumerant], CamelCase);
353 let enumerant_parse_operation;
354 if enumerant.parameters.is_empty() {
355 enumerant_items.push(quote!{
356 #[derive(Clone, Debug, Default)]
357 pub struct #type_name;
359 enumerant_parse_operation = quote!{(Some(#type_name), words)};
361 let mut enumerant_member_declarations = Vec::new();
362 let mut enumerant_member_parse_initializers = Vec::new();
363 let mut parse_enumerant_members = Vec::new();
364 for (index, parameter) in enumerant.parameters.iter().enumerate() {
365 let name = new_id(format!("parameter_{}", index), SnakeCase);
366 let kind = new_id(¶meter.kind, CamelCase);
367 enumerant_member_declarations.push(quote!{
370 enumerant_member_parse_initializers.push(quote!{
373 parse_enumerant_members.push(quote!{
374 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
377 enumerant_items.push(quote!{
378 #[derive(Clone, Debug, Default)]
379 pub struct #type_name(#(#enumerant_member_declarations)*);
381 enumerant_parse_operation = quote!{
382 #(#parse_enumerant_members)*
383 (Some(#type_name(#(#enumerant_member_parse_initializers)*)), words)
386 enumerant_members.push(quote!{
387 pub #member_name: Option<#type_name>
389 let enumerant_value = enumerant.value;
390 enumerant_parse_operations.push(quote!{
391 let (#member_name, words) = if (mask & #enumerant_value) != 0 {
392 mask &= !#enumerant_value;
393 #enumerant_parse_operation
403 #[derive(Clone, Debug, Default)]
404 pub struct #kind_id {
405 #(#enumerant_members),*
410 let parse_body = quote!{
411 let (mut mask, words) = u32::spirv_parse(words, parse_state)?;
412 #(#enumerant_parse_operations)*
414 Err(Error::InvalidEnumValue)
417 #(#enumerant_member_names,)*
425 impl SPIRVParse for #kind_id {
428 parse_state: &mut ParseState,
429 ) -> Result<(Self, &'a [u32])> {
436 ast::OperandKind::ValueEnum { kind, enumerants } => {
437 let kind_id = new_id(&kind, CamelCase);
438 let mut generated_enumerants = Vec::new();
439 let mut enumerant_parse_cases = Vec::new();
440 for enumerant in enumerants {
441 let name = new_enumerant_id(&kind, &enumerant.enumerant);
442 let enumerant_value = enumerant.value;
443 if enumerant.parameters.is_empty() {
444 generated_enumerants.push(quote!{#name});
445 enumerant_parse_cases.push(quote!{
446 #enumerant_value => Ok((#kind_id::#name, words)),
449 let mut enumerant_member_declarations = Vec::new();
450 let mut enumerant_member_parse_initializers = Vec::new();
451 let mut parse_enumerant_members = Vec::new();
452 for parameter in enumerant.parameters.iter() {
453 let name = new_id(parameter.name.as_ref().unwrap(), SnakeCase);
454 let kind = new_id(¶meter.kind, CamelCase);
455 enumerant_member_declarations.push(quote!{
458 enumerant_member_parse_initializers.push(quote!{
461 parse_enumerant_members.push(quote!{
462 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
465 generated_enumerants.push(quote!{
467 #(#enumerant_member_declarations)*
470 enumerant_parse_cases.push(quote!{
471 #enumerant_value => {
472 #(#parse_enumerant_members)*
473 Ok((#kind_id::#name {
474 #(#enumerant_member_parse_initializers)*
484 #[derive(Clone, Debug)]
486 #(#generated_enumerants,)*
494 impl SPIRVParse for #kind_id {
497 parse_state: &mut ParseState,
498 ) -> Result<(Self, &'a [u32])> {
499 let (enumerant, words) = u32::spirv_parse(words, parse_state)?;
501 #(#enumerant_parse_cases)*
502 _ => Err(Error::InvalidEnumValue),
509 ast::OperandKind::Id { kind, doc: _ } => {
510 let base = if *kind == ast::Kind::IdRef {
515 let kind_id = new_id(kind, CamelCase);
520 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
522 pub struct #kind_id(pub #base);
525 if *kind != ast::Kind::IdRef {
530 impl SPIRVParse for #kind_id {
533 parse_state: &mut ParseState,
534 ) -> Result<(Self, &'a [u32])> {
535 IdRef::spirv_parse(words, parse_state).map(|(value, words)| (#kind_id(value), words))
544 impl fmt::Display for #kind_id {
545 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
546 fmt::Display::fmt(&self.0, f)
553 ast::OperandKind::Literal { kind, doc: _ } => {
554 let kind_id = new_id(kind, CamelCase);
559 ast::LiteralKind::LiteralInteger
560 | ast::LiteralKind::LiteralContextDependentNumber => unreachable!(),
561 ast::LiteralKind::LiteralInteger32
562 | ast::LiteralKind::LiteralContextDependentNumber32 => {
563 quote!{pub type #kind_id = u32;}
565 ast::LiteralKind::LiteralInteger64
566 | ast::LiteralKind::LiteralContextDependentNumber64 => {
567 quote!{pub type #kind_id = u64;}
569 ast::LiteralKind::LiteralString => quote!{pub type #kind_id = String;},
570 ast::LiteralKind::LiteralExtInstInteger => {
571 quote!{pub type #kind_id = u32;}
573 ast::LiteralKind::LiteralSpecConstantOpInteger => continue,
577 ast::OperandKind::Composite { kind, bases } => {
578 let kind = new_id(kind, CamelCase);
579 let bases = bases.into_iter().map(|base| new_id(base, CamelCase));
580 writeln!(&mut out, "{}", quote!{pub type #kind = (#(#bases),*);})?;
585 let mut instruction_enumerants = Vec::new();
586 let mut spec_constant_op_instruction_enumerants = Vec::new();
587 let mut instruction_parse_cases = Vec::new();
588 for instruction in core_instructions.iter() {
589 let opcode = instruction.opcode;
590 let opname = new_id(remove_initial_op(instruction.opname.as_ref()), CamelCase);
591 instruction_parse_cases.push(match &instruction.opname {
592 ast::InstructionName::OpTypeInt => {
594 let id_state = match width {
595 8 | 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
596 64 => IdState::Type(IdStateType(BitWidth::Width64)),
597 _ => return Err(Error::UnsupportedIntSize),
599 parse_state.define_id(id_result, id_state)?;
600 if words.is_empty() {
601 Ok(Instruction::TypeInt {
607 Err(Error::InstructionTooLong)
612 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
613 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
614 let (signedness, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
619 ast::InstructionName::OpTypeFloat => {
622 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
623 let (width, words) = LiteralInteger32::spirv_parse(words, parse_state)?;
624 let id_state = match width {
625 16 | 32 => IdState::Type(IdStateType(BitWidth::Width32OrLess)),
626 64 => IdState::Type(IdStateType(BitWidth::Width64)),
627 _ => return Err(Error::UnsupportedFloatSize),
629 parse_state.define_id(id_result, id_state)?;
630 if words.is_empty() {
631 Ok(Instruction::TypeFloat {
636 Err(Error::InstructionTooLong)
641 ast::InstructionName::OpSwitch32 => {
643 IdState::Value(IdStateValue(BitWidth::Width32OrLess)) => {
644 let (target, words) = Vec::<PairLiteralInteger32IdRef>::spirv_parse(words, parse_state)?;
645 if words.is_empty() {
646 Ok(Instruction::Switch32 {
652 Err(Error::InstructionTooLong)
657 IdState::Value(IdStateValue(BitWidth::Width64)) => {
658 let (target, words) = Vec::<PairLiteralInteger64IdRef>::spirv_parse(words, parse_state)?;
659 if words.is_empty() {
660 Ok(Instruction::Switch64 {
666 Err(Error::InstructionTooLong)
672 let (selector, words) = IdRef::spirv_parse(words, parse_state)?;
673 let (default, words) = IdRef::spirv_parse(words, parse_state)?;
674 match parse_state.id_states[selector.0 as usize] {
677 _ => Err(Error::SwitchSelectorIsInvalid(selector)),
682 ast::InstructionName::OpSwitch64 => quote!{},
683 ast::InstructionName::OpConstant32 => {
685 IdStateType(BitWidth::Width32OrLess) => {
686 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
687 if words.is_empty() {
688 Ok(Instruction::Constant32 {
694 Err(Error::InstructionTooLong)
699 IdStateType(BitWidth::Width64) => {
700 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
701 if words.is_empty() {
702 Ok(Instruction::Constant64 {
708 Err(Error::InstructionTooLong)
714 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
715 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
716 parse_state.define_value(id_result_type, id_result)?;
717 match parse_state.get_type(id_result_type.0)? {
724 ast::InstructionName::OpConstant64 => quote!{},
725 ast::InstructionName::OpSpecConstant32 => {
727 IdStateType(BitWidth::Width32OrLess) => {
728 let (value, words) = LiteralContextDependentNumber32::spirv_parse(words, parse_state)?;
729 if words.is_empty() {
730 Ok(Instruction::SpecConstant32 {
736 Err(Error::InstructionTooLong)
741 IdStateType(BitWidth::Width64) => {
742 let (value, words) = LiteralContextDependentNumber64::spirv_parse(words, parse_state)?;
743 if words.is_empty() {
744 Ok(Instruction::SpecConstant64 {
750 Err(Error::InstructionTooLong)
756 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
757 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
758 parse_state.define_value(id_result_type, id_result)?;
759 match parse_state.get_type(id_result_type.0)? {
766 ast::InstructionName::OpSpecConstant64 => quote!{},
767 ast::InstructionName::OpSpecConstantOp => {
769 let (operation, words) = OpSpecConstantOp::spirv_parse(words, parse_state)?;
770 if words.is_empty() {
771 Ok(Instruction::#opname { operation })
773 Err(Error::InstructionTooLong)
778 let mut parse_operations = Vec::new();
779 let mut operand_names = Vec::new();
780 for operand in &instruction.operands {
781 let kind = new_id(&operand.kind, CamelCase);
782 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
783 let kind = match operand.quantifier {
784 None => quote!{#kind},
785 Some(ast::Quantifier::Optional) => quote!{Option::<#kind>},
786 Some(ast::Quantifier::Variadic) => quote!{Vec::<#kind>},
788 parse_operations.push(quote!{
789 let (#name, words) = #kind::spirv_parse(words, parse_state)?;
791 operand_names.push(name);
793 if let Some([operand1, operand2]) = instruction.operands.get(..2) {
794 if operand1.kind == ast::Kind::IdResultType && operand2.kind == ast::Kind::IdResult {
795 let operand1_name = new_id(operand1.name.as_ref().unwrap(), SnakeCase);
796 let operand2_name = new_id(operand2.name.as_ref().unwrap(), SnakeCase);
797 parse_operations.push(quote!{
798 parse_state.define_value(#operand1_name, #operand2_name)?;
803 #(#parse_operations)*
804 if words.is_empty() {
805 Ok(Instruction::#opname {
809 Err(Error::InstructionTooLong)
814 let instruction_enumerant =
815 if instruction.opname == ast::InstructionName::OpSpecConstantOp {
818 operation: OpSpecConstantOp,
821 } else if instruction.operands.is_empty() {
824 let mut fields = Vec::new();
825 for operand in instruction.operands.iter() {
826 let kind = new_id(&operand.kind, CamelCase);
827 let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
828 let kind = match &operand.quantifier {
829 None => quote!{#kind},
830 Some(ast::Quantifier::Optional) => quote!{Option<#kind>},
831 Some(ast::Quantifier::Variadic) => quote!{Vec<#kind>},
833 fields.push(quote!{#name: #kind});
841 if ast::OP_SPEC_CONSTANT_OP_SUPPORTED_INSTRUCTIONS.contains(&instruction.opname) {
842 spec_constant_op_instruction_enumerants.push(instruction_enumerant.clone());
844 instruction_enumerants.push(instruction_enumerant);
850 #[derive(Clone, Debug)]
851 pub enum OpSpecConstantOp {
852 #(#spec_constant_op_instruction_enumerants,)*
860 #[derive(Clone, Debug)]
861 pub enum Instruction {
862 #(#instruction_enumerants,)*
870 #[derive(Copy, Clone, Debug)]
872 pub version: (u32, u32),
875 pub instruction_schema: u32,
878 impl fmt::Display for Header {
879 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
880 writeln!(f, "; SPIR-V")?;
881 writeln!(f, "; Version: {}.{}", self.version.0, self.version.1)?;
882 writeln!(f, "; Generator: {:#X}", self.generator)?;
883 writeln!(f, "; Bound: {}", self.bound)?;
884 writeln!(f, "; Schema: {}", self.instruction_schema)
888 struct InstructionIndentAndResult(Option<IdResult>);
890 impl fmt::Display for InstructionIndentAndResult {
891 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892 write!(f, "{:>15}", self.0.map(|v| format!("{} = ", v.0)).unwrap_or_default())
896 impl fmt::Display for IdRef {
897 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
898 write!(f, "#{}", self.0)
902 #[derive(Clone, Debug)]
906 UnsupportedVersion(u32, u32),
907 ZeroInstructionLength,
908 SourcePrematurelyEnded,
910 Utf8Error(Utf8Error),
911 InstructionPrematurelyEnded,
912 InvalidStringTermination,
916 IdAlreadyDefined(IdResult),
917 UnsupportedFloatSize,
919 UndefinedType(IdRef),
920 SwitchSelectorIsInvalid(IdRef),
923 impl From<Utf8Error> for Error {
924 fn from(v: Utf8Error) -> Self {
929 impl From<FromUtf8Error> for Error {
930 fn from(v: FromUtf8Error) -> Self {
931 Error::Utf8Error(v.utf8_error())
935 impl fmt::Display for Error {
936 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
938 Error::MissingHeader => write!(f, "SPIR-V source is missing the file header"),
939 Error::InvalidHeader => write!(f, "SPIR-V source has an invalid file header"),
940 Error::UnsupportedVersion(major, minor) => write!(
942 "SPIR-V source has an unsupported version: {}.{}",
946 Error::ZeroInstructionLength => write!(f, "SPIR-V instruction has a length of zero"),
947 Error::SourcePrematurelyEnded => write!(f, "SPIR-V source prematurely ended"),
948 Error::UnknownOpcode(opcode) => {
949 write!(f, "SPIR-V instruction has an unknown opcode: {}", opcode)
951 Error::Utf8Error(error) => fmt::Display::fmt(&error, f),
952 Error::InstructionPrematurelyEnded => write!(f, "SPIR-V instruction prematurely ended"),
953 Error::InvalidStringTermination => write!(f, "SPIR-V LiteralString has an invalid termination word"),
954 Error::InstructionTooLong => write!(f, "SPIR-V instruction is too long"),
955 Error::InvalidEnumValue => write!(f, "enum has invalid value"),
956 Error::IdOutOfBounds(id) => write!(f, "id is out of bounds: {}", id),
957 Error::IdAlreadyDefined(id) => write!(f, "id is already defined: {}", id),
958 Error::UnsupportedFloatSize => write!(f, "unsupported float size"),
959 Error::UnsupportedIntSize => write!(f, "unsupported int size"),
960 Error::UndefinedType(id) => write!(f, "undefined type {}", id),
961 Error::SwitchSelectorIsInvalid(id) => write!(f, "Switch selector is invalid: {}", id),
966 impl error::Error for Error {}
968 type Result<T> = result::Result<T, Error>;
970 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
976 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
977 struct IdStateType(BitWidth);
979 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
980 struct IdStateValue(BitWidth);
982 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
989 #[derive(Clone, Debug)]
991 id_states: Vec<IdState>,
995 fn define_id(&mut self, id_result: IdResult, new_id_state: IdState) -> Result<()> {
996 let id_state = &mut self.id_states[(id_result.0).0 as usize];
997 if *id_state != IdState::Unknown {
998 return Err(Error::IdAlreadyDefined(id_result));
1000 *id_state = new_id_state;
1003 fn get_type(&self, id: IdRef) -> Result<IdStateType> {
1004 if let IdState::Type(retval) = self.id_states[id.0 as usize] {
1007 Err(Error::UndefinedType(id))
1010 fn define_value(&mut self, id_result_type: IdResultType, id_result: IdResult) -> Result<()> {
1011 if let IdState::Type(IdStateType(bit_width)) = self.id_states[(id_result_type.0).0 as usize] {
1012 self.define_id(id_result, IdState::Value(IdStateValue(bit_width)))?;
1018 #[derive(Clone, Debug)]
1019 pub struct Parser<'a> {
1022 parse_state: ParseState,
1025 fn parse_version(v: u32) -> Result<(u32, u32)> {
1026 if (v & 0xFF0000FF) != 0 {
1027 return Err(Error::InvalidHeader);
1029 let major = (v >> 16) & 0xFF;
1030 let minor = (v >> 8) & 0xFF;
1034 impl<'a> Parser<'a> {
1035 pub fn header(&self) -> &Header {
1038 pub fn start(mut words: &'a [u32]) -> Result<Self> {
1039 let header = words.get(0..5).ok_or(Error::MissingHeader)?;
1040 words = &words[5..];
1041 let header = match *header {
1042 [MAGIC_NUMBER, version, generator, bound, instruction_schema @ 0] if bound >= 1 => {
1043 let version = parse_version(version)?;
1044 if version.0 != MAJOR_VERSION || version.1 > MINOR_VERSION {
1045 return Err(Error::UnsupportedVersion(version.0, version.1));
1054 _ => return Err(Error::InvalidHeader),
1059 parse_state: ParseState {
1060 id_states: vec![IdState::Unknown; header.bound as usize],
1064 fn next_helper(&mut self, length_and_opcode: u32) -> Result<Instruction> {
1065 let length = (length_and_opcode >> 16) as usize;
1066 let opcode = length_and_opcode as u16;
1068 return Err(Error::ZeroInstructionLength);
1070 let instruction_words = self.words.get(1..length).ok_or(Error::SourcePrematurelyEnded)?;
1071 self.words = &self.words[length..];
1072 parse_instruction(opcode, instruction_words, &mut self.parse_state)
1076 impl<'a> Iterator for Parser<'a> {
1077 type Item = Result<Instruction>;
1078 fn next(&mut self) -> Option<Result<Instruction>> {
1079 let length_and_opcode = self.words.get(0)?;
1080 Some(self.next_helper(*length_and_opcode))
1089 fn parse_instruction(opcode: u16, words: &[u32], parse_state: &mut ParseState) -> Result<Instruction> {
1091 #(#instruction_parse_cases)*
1092 opcode => Err(Error::UnknownOpcode(opcode)),
1101 impl SPIRVParse for OpSpecConstantOp {
1104 parse_state: &mut ParseState
1105 ) -> Result<(Self, &'a [u32])> {
1106 let (id_result_type, words) = IdResultType::spirv_parse(words, parse_state)?;
1107 let (id_result, words) = IdResult::spirv_parse(words, parse_state)?;
1108 let (opcode, words) = u32::spirv_parse(words, parse_state)?;
1115 let source = String::from_utf8(out).unwrap();
1116 let source = match format_source(&options, &source) {
1117 Ok(source) => source.into_owned(),
1119 eprintln!("formatting source failed: {}", error);