1use crate::dr;
2use crate::grammar;
3use crate::spirv;
4
5use super::{
6 decoder,
7 tracker::{Type, TypeTracker},
8 DecodeError,
9};
10use std::{error, fmt, result, slice};
11
12use crate::grammar::CoreInstructionTable as GInstTable;
13use crate::grammar::OperandKind as GOpKind;
14use crate::grammar::OperandQuantifier as GOpCount;
15
16use crate::utils::version;
17
18type GInstRef = &'static grammar::Instruction<'static>;
19
20const WORD_NUM_BYTES: usize = 4;
21
22#[derive(Debug)]
27pub enum State {
28 Complete,
30 ConsumerStopRequested,
32 ConsumerError(Box<dyn error::Error + Send + Sync>),
34 HeaderIncomplete(DecodeError),
36 HeaderIncorrect,
38 EndiannessUnsupported,
40 WordCountZero(usize, usize),
42 OpcodeUnknown(usize, usize, u16),
44 OperandExpected(usize, usize),
46 OperandExceeded(usize, usize),
48 OperandError(DecodeError),
50 TypeUnsupported(usize, usize),
52 SpecConstantOpIntegerIncorrect(usize, usize),
54}
55
56impl From<DecodeError> for State {
57 fn from(err: DecodeError) -> Self {
58 State::OperandError(err)
59 }
60}
61
62impl error::Error for State {}
63
64impl fmt::Display for State {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 match *self {
67 State::Complete => write!(f, "completed parsing"),
68 State::ConsumerStopRequested => write!(f, "stop parsing requested by consumer"),
69 State::ConsumerError(ref err) => write!(f, "consumer error: {}", err),
70 State::HeaderIncomplete(ref err) => write!(f, "incomplete module header: {}", err),
71 State::HeaderIncorrect => write!(f, "incorrect module header"),
72 State::EndiannessUnsupported => write!(f, "unsupported endianness"),
73 State::WordCountZero(offset, index) => write!(
74 f,
75 "zero word count found for instruction #{} at offset {}",
76 index, offset
77 ),
78 State::OpcodeUnknown(offset, index, opcode) => write!(
79 f,
80 "unknown opcode ({}) for instruction #{} at offset {}",
81 opcode, index, offset
82 ),
83 State::OperandExpected(offset, index) => write!(
84 f,
85 "expected more operands for instruction #{} at offset {}",
86 index, offset
87 ),
88 State::OperandExceeded(offset, index) => write!(
89 f,
90 "found extra operands for instruction #{} at offset {}",
91 index, offset
92 ),
93 State::OperandError(ref err) => write!(f, "operand decoding error: {}", err),
94 State::TypeUnsupported(offset, index) => write!(
95 f,
96 "unsupported type for instruction #{} at offset {}",
97 index, offset
98 ),
99 State::SpecConstantOpIntegerIncorrect(offset, index) => write!(
100 f,
101 "incorrect SpecConstantOp number for instruction #{} at offset {}",
102 index, offset
103 ),
104 }
105 }
106}
107
108pub type Result<T> = result::Result<T, State>;
109
110const HEADER_NUM_WORDS: usize = 5;
111
112#[derive(Debug)]
114pub enum Action {
115 Continue,
117 Stop,
119 Error(Box<dyn error::Error + Send + Sync>),
121}
122
123impl Action {
124 fn consume(self) -> Result<()> {
125 match self {
126 Action::Continue => Ok(()),
127 Action::Stop => Err(State::ConsumerStopRequested),
128 Action::Error(err) => Err(State::ConsumerError(err)),
129 }
130 }
131}
132
133pub trait Consumer {
145 fn initialize(&mut self) -> Action;
147 fn finalize(&mut self) -> Action;
149
150 fn consume_header(&mut self, module: dr::ModuleHeader) -> Action;
152 fn consume_instruction(&mut self, inst: dr::Instruction) -> Action;
154}
155
156pub fn parse_bytes(binary: impl AsRef<[u8]>, consumer: &mut dyn Consumer) -> Result<()> {
159 Parser::new(binary.as_ref(), consumer).parse()
160}
161
162pub fn parse_words(binary: impl AsRef<[u32]>, consumer: &mut dyn Consumer) -> Result<()> {
165 let len = binary.as_ref().len() * 4;
166 let buf = unsafe { slice::from_raw_parts(binary.as_ref().as_ptr() as *const u8, len) };
167 Parser::new(buf, consumer).parse()
168}
169
170pub struct Parser<'c, 'd> {
213 decoder: decoder::Decoder<'d>,
214 consumer: &'c mut dyn Consumer,
215 type_tracker: TypeTracker,
216 inst_index: usize,
220}
221
222impl<'c, 'd> Parser<'c, 'd> {
223 pub fn new(binary: &'d [u8], consumer: &'c mut dyn Consumer) -> Self {
226 Parser {
227 decoder: decoder::Decoder::new(binary),
228 consumer,
229 type_tracker: TypeTracker::new(),
230 inst_index: 0,
231 }
232 }
233
234 pub fn parse(mut self) -> Result<()> {
236 self.consumer.initialize().consume()?;
237 let header = self.parse_header()?;
238 self.consumer.consume_header(header).consume()?;
239
240 loop {
241 let result = self.parse_inst();
242 match result {
243 Ok(inst) => {
244 self.type_tracker.track(&inst);
245 self.consumer.consume_instruction(inst).consume()?;
246 }
247 Err(State::Complete) => break,
248 Err(error) => return Err(error),
249 };
250 }
251 self.consumer.finalize().consume()
252 }
253
254 fn split_into_word_count_and_opcode(word: spirv::Word) -> (u16, u16) {
255 ((word >> 16) as u16, (word & 0xffff) as u16)
256 }
257
258 fn parse_header(&mut self) -> Result<dr::ModuleHeader> {
259 match self.decoder.words(HEADER_NUM_WORDS) {
260 Ok(words) => {
261 if words[0] != spirv::MAGIC_NUMBER {
262 if words[0] == spirv::MAGIC_NUMBER.swap_bytes() {
263 return Err(State::EndiannessUnsupported);
264 } else {
265 return Err(State::HeaderIncorrect);
266 }
267 }
268
269 let mut header = dr::ModuleHeader::new(words[3]);
270 let (major, minor) = version::create_version_from_word(words[1]);
271 header.set_version(major, minor);
272
273 Ok(header)
274 }
275 Err(err) => Err(State::HeaderIncomplete(err)),
276 }
277 }
278
279 fn parse_inst(&mut self) -> Result<dr::Instruction> {
280 self.inst_index += 1;
281 if let Ok(word) = self.decoder.word() {
282 let (wc, opcode) = Parser::split_into_word_count_and_opcode(word);
283 if wc == 0 {
284 return Err(State::WordCountZero(
285 self.decoder.offset() - WORD_NUM_BYTES,
286 self.inst_index,
287 ));
288 }
289 if let Some(grammar) = GInstTable::lookup_opcode(opcode) {
290 self.decoder.set_limit((wc - 1) as usize);
291 let result = self.parse_operands(grammar)?;
292 if !self.decoder.limit_reached() {
293 return Err(State::OperandExceeded(
294 self.decoder.offset(),
295 self.inst_index,
296 ));
297 }
298 self.decoder.clear_limit();
299 Ok(result)
300 } else {
301 Err(State::OpcodeUnknown(
302 self.decoder.offset() - WORD_NUM_BYTES,
303 self.inst_index,
304 opcode,
305 ))
306 }
307 } else {
308 Err(State::Complete)
309 }
310 }
311
312 fn parse_literal(&mut self, type_id: spirv::Word) -> Result<dr::Operand> {
313 let tracked_type = self.type_tracker.resolve(type_id);
314 match tracked_type {
315 Some(t) => match t {
316 Type::Integer(size, _) => match size {
317 8 => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
319 16 => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
320 32 => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
321 64 => Ok(dr::Operand::LiteralBit64(self.decoder.bit64()?)),
322 _ => Err(State::TypeUnsupported(
323 self.decoder.offset(),
324 self.inst_index,
325 )),
326 },
327 Type::Float(size) => match size {
328 16 => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
329 32 => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
330 64 => Ok(dr::Operand::LiteralBit64(self.decoder.bit64()?)),
331 _ => Err(State::TypeUnsupported(
332 self.decoder.offset(),
333 self.inst_index,
334 )),
335 },
336 },
337 None => Ok(dr::Operand::LiteralBit32(self.decoder.bit32()?)),
340 }
341 }
342
343 fn parse_spec_constant_op(&mut self) -> Result<Vec<dr::Operand>> {
344 let mut operands = vec![];
345
346 let number = self.decoder.bit32()?;
347 if let Some(g) = GInstTable::lookup_opcode(number as u16) {
348 operands.push(dr::Operand::LiteralSpecConstantOpInteger(g.opcode));
350
351 for loperand in g.operands {
353 if loperand.kind != GOpKind::IdResultType && loperand.kind != GOpKind::IdResult {
354 operands.append(&mut self.parse_operand(loperand.kind)?);
355 }
356 }
357 Ok(operands)
358 } else {
359 Err(State::SpecConstantOpIntegerIncorrect(
360 self.decoder.offset(),
361 self.inst_index,
362 ))
363 }
364 }
365
366 fn parse_operands(&mut self, grammar: GInstRef) -> Result<dr::Instruction> {
367 let mut rtype = None;
368 let mut rid = None;
369 let mut coperands = vec![]; let mut loperand_index: usize = 0; while loperand_index < grammar.operands.len() {
373 let loperand = &grammar.operands[loperand_index];
374 let has_more_coperands = !self.decoder.limit_reached();
375 if has_more_coperands {
376 match loperand.kind {
377 GOpKind::IdResultType => rtype = Some(self.decoder.id()?),
378 GOpKind::IdResult => rid = Some(self.decoder.id()?),
379 GOpKind::LiteralContextDependentNumber => {
380 assert!(
384 grammar.opcode == spirv::Op::Constant
385 || grammar.opcode == spirv::Op::SpecConstant
386 );
387 let id = rtype.expect(
388 "internal error: \
389 should already decoded result type id before context dependent number",
390 );
391 coperands.push(self.parse_literal(id)?)
392 }
393 GOpKind::PairLiteralIntegerIdRef => {
394 assert_eq!(grammar.opcode, spirv::Op::Switch);
395 let selector = match coperands[0] {
396 dr::Operand::IdRef(id) => id,
397 _ => panic!("internal error: OpSwitch selector should be IdRef"),
398 };
399 coperands.push(self.parse_literal(selector)?);
400 coperands.push(dr::Operand::IdRef(self.decoder.id()?));
401 }
402 GOpKind::LiteralSpecConstantOpInteger => {
403 coperands.append(&mut self.parse_spec_constant_op()?)
404 }
405 _ => coperands.append(&mut self.parse_operand(loperand.kind)?),
406 }
407 match loperand.quantifier {
408 GOpCount::One | GOpCount::ZeroOrOne => loperand_index += 1,
409 GOpCount::ZeroOrMore => continue,
410 }
411 } else {
412 match loperand.quantifier {
414 GOpCount::One => {
415 return Err(State::OperandExpected(
416 self.decoder.offset(),
417 self.inst_index,
418 ))
419 }
420 GOpCount::ZeroOrOne | GOpCount::ZeroOrMore => break,
421 }
422 }
423 }
424 Ok(dr::Instruction::new(grammar.opcode, rtype, rid, coperands))
425 }
426}
427
428include!("autogen_parse_operand.rs");
429
430#[cfg(test)]
431mod tests {
432 use assert_matches::assert_matches;
433
434 use crate::dr;
435 use crate::spirv;
436
437 use super::{parse_words, Action, Consumer, Parser, State, WORD_NUM_BYTES};
438 use crate::binary::DecodeError;
439 use std::{error, fmt};
440
441 #[rustfmt::skip]
444 static ZERO_BOUND_HEADER: &[u8] = &[
445 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00,
447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449 0x00, 0x00, 0x00, 0x00];
451
452 struct RetainingConsumer {
453 pub header: Option<dr::ModuleHeader>,
454 pub insts: Vec<dr::Instruction>,
455 }
456 impl RetainingConsumer {
457 fn new() -> RetainingConsumer {
458 RetainingConsumer {
459 header: None,
460 insts: vec![],
461 }
462 }
463 }
464 impl Consumer for RetainingConsumer {
465 fn initialize(&mut self) -> Action {
466 Action::Continue
467 }
468 fn finalize(&mut self) -> Action {
469 Action::Continue
470 }
471
472 fn consume_header(&mut self, header: dr::ModuleHeader) -> Action {
473 self.header = Some(header);
474 Action::Continue
475 }
476 fn consume_instruction(&mut self, inst: dr::Instruction) -> Action {
477 self.insts.push(inst);
478 Action::Continue
479 }
480 }
481
482 fn w2b(word: spirv::Word) -> Vec<u8> {
485 (0..WORD_NUM_BYTES)
486 .map(|i| ((word >> (8 * i)) & 0xff) as u8)
487 .collect()
488 }
489
490 struct ModuleBuilder {
492 insts: Vec<u8>,
493 }
494 impl ModuleBuilder {
495 fn new() -> ModuleBuilder {
496 ModuleBuilder {
497 insts: ZERO_BOUND_HEADER.to_vec(),
498 }
499 }
500
501 fn inst(&mut self, opcode: spirv::Op, operands: Vec<u32>) {
504 let count: u32 = operands.len() as u32 + 1;
505 self.insts.append(&mut w2b((count << 16) | (opcode as u32)));
506 for o in operands {
507 self.insts.append(&mut w2b(o));
508 }
509 }
510
511 fn get(&self) -> &[u8] {
513 &self.insts
514 }
515 }
516
517 #[test]
518 fn test_module_builder() {
519 let mut b = ModuleBuilder::new();
520 b.inst(spirv::Op::Nop, vec![]);
522 b.inst(spirv::Op::Capability, vec![22]);
524 b.inst(spirv::Op::MemoryModel, vec![0, 1]);
526 let mut module = ZERO_BOUND_HEADER.to_vec();
527 module.append(&mut vec![0x00, 0x00, 0x01, 0x00]); module.append(&mut vec![0x11, 0x00, 0x02, 0x00]); module.append(&mut vec![0x16, 0x00, 0x00, 0x00]); module.append(&mut vec![0x0e, 0x00, 0x03, 0x00]); module.append(&mut vec![0x00, 0x00, 0x00, 0x00]); module.append(&mut vec![0x01, 0x00, 0x00, 0x00]); assert_eq!(module, b.get());
534 }
535
536 #[test]
537 fn test_parsing_empty_binary() {
538 let v = vec![];
539 let mut c = RetainingConsumer::new();
540 let p = Parser::new(&v, &mut c);
541 assert_matches!(
542 p.parse(),
543 Err(State::HeaderIncomplete(DecodeError::StreamExpected(0)))
544 );
545 }
546
547 #[test]
548 fn test_parsing_incomplete_header() {
549 let v = vec![0x03, 0x02, 0x23, 0x07];
550 let mut c = RetainingConsumer::new();
551 let p = Parser::new(&v, &mut c);
552 assert_matches!(
553 p.parse(),
554 Err(State::HeaderIncomplete(DecodeError::StreamExpected(4)))
555 );
556 }
557
558 #[test]
559 fn test_parsing_unsupported_endianness() {
560 let mut module = ZERO_BOUND_HEADER.to_vec();
561 module.as_mut_slice().swap(0, 3);
562 module.as_mut_slice().swap(1, 2);
563 let mut c = RetainingConsumer::new();
564 let p = Parser::new(&module, &mut c);
565 assert_matches!(p.parse(), Err(State::EndiannessUnsupported));
566 }
567
568 #[test]
569 fn test_parsing_wrong_magic_number() {
570 let mut module = ZERO_BOUND_HEADER.to_vec();
571 module[0] = 0x00;
572 let mut c = RetainingConsumer::new();
573 let p = Parser::new(&module, &mut c);
574 assert_matches!(p.parse(), Err(State::HeaderIncorrect));
575 }
576
577 #[test]
578 fn test_parsing_complete_header() {
579 let mut c = RetainingConsumer::new();
580 {
581 let p = Parser::new(ZERO_BOUND_HEADER, &mut c);
582 assert_matches!(p.parse(), Ok(()));
583 }
584 let mut header = dr::ModuleHeader::new(0);
585 header.set_version(1, 0);
586 assert_eq!(Some(header), c.header);
587 }
588
589 #[test]
590 fn test_parsing_one_inst() {
591 let mut c = RetainingConsumer::new();
592 {
593 let mut b = ModuleBuilder::new();
594 b.inst(spirv::Op::MemoryModel, vec![0, 1]);
596 let p = Parser::new(b.get(), &mut c);
597 assert_matches!(p.parse(), Ok(()));
598 }
599 assert_eq!(1, c.insts.len());
600 let inst = &c.insts[0];
601 assert_eq!("MemoryModel", inst.class.opname);
602 assert_eq!(None, inst.result_type);
603 assert_eq!(None, inst.result_id);
604 assert_eq!(
605 vec![
606 dr::Operand::AddressingModel(spirv::AddressingModel::Logical),
607 dr::Operand::MemoryModel(spirv::MemoryModel::GLSL450)
608 ],
609 inst.operands
610 );
611 }
612
613 #[test]
614 fn test_parsing_zero_word_count() {
615 let mut v = ZERO_BOUND_HEADER.to_vec();
616 v.append(&mut vec![0x00, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
618 let p = Parser::new(&v, &mut c);
619 assert_matches!(p.parse(), Err(State::WordCountZero(20, 1)));
621 }
622
623 #[test]
624 fn test_parsing_extra_operand() {
625 let mut v = ZERO_BOUND_HEADER.to_vec();
626 v.append(&mut vec![0x00, 0x00, 0x01, 0x00]); v.append(&mut vec![0x00, 0x00, 0x02, 0x00]); v.append(&mut vec![0x00, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
630 let p = Parser::new(&v, &mut c);
631 assert_matches!(p.parse(), Err(State::OperandExceeded(28, 2)));
634 }
635
636 #[test]
637 fn test_parsing_missing_operand() {
638 let mut v = ZERO_BOUND_HEADER.to_vec();
639 v.append(&mut vec![0x00, 0x00, 0x01, 0x00]); v.append(&mut vec![0x0e, 0x00, 0x03, 0x00]); v.append(&mut vec![0x00, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
643 let p = Parser::new(&v, &mut c);
644 assert_matches!(
647 p.parse(),
648 Err(State::OperandError(DecodeError::StreamExpected(32)))
649 );
650 }
651
652 #[test]
653 fn test_parsing_operand_parameters() {
654 let mut v = ZERO_BOUND_HEADER.to_vec();
655 v.append(&mut vec![0x47, 0x00, 0x04, 0x00]); v.append(&mut vec![0x05, 0x00, 0x00, 0x00]); v.append(&mut vec![0x0b, 0x00, 0x00, 0x00]); v.append(&mut vec![0x06, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
660 {
661 let p = Parser::new(&v, &mut c);
662 assert_matches!(p.parse(), Ok(()));
663 }
664 assert_eq!(1, c.insts.len());
665 let inst = &c.insts[0];
666 assert_eq!("Decorate", inst.class.opname);
667 assert_eq!(None, inst.result_type);
668 assert_eq!(None, inst.result_id);
669 assert_eq!(
670 vec![
671 dr::Operand::IdRef(5),
672 dr::Operand::Decoration(spirv::Decoration::BuiltIn),
673 dr::Operand::BuiltIn(spirv::BuiltIn::InstanceId)
674 ],
675 inst.operands
676 );
677 }
678
679 #[test]
680 fn test_parsing_missing_operand_parameters() {
681 let mut v = ZERO_BOUND_HEADER.to_vec();
682 v.append(&mut vec![0x47, 0x00, 0x03, 0x00]); v.append(&mut vec![0x05, 0x00, 0x00, 0x00]); v.append(&mut vec![0x0b, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
686 let p = Parser::new(&v, &mut c);
687 assert_matches!(
688 p.parse(),
689 Err(State::OperandError(DecodeError::StreamExpected(32)))
690 );
691 }
692
693 #[test]
694 fn test_parsing_with_all_optional_operands() {
695 let mut v = ZERO_BOUND_HEADER.to_vec();
696 v.append(&mut vec![0x03, 0x00, 0x05, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0xc2, 0x01, 0x00, 0x00]); v.append(&mut vec![0x06, 0x00, 0x00, 0x00]); v.append(&mut b"wow".to_vec()); v.push(0x00); let mut c = RetainingConsumer::new();
703 {
704 let p = Parser::new(&v, &mut c);
705 assert_matches!(p.parse(), Ok(()));
706 }
707 assert_eq!(1, c.insts.len());
708 let inst = &c.insts[0];
709 assert_eq!("Source", inst.class.opname);
710 assert_eq!(None, inst.result_type);
711 assert_eq!(None, inst.result_id);
712 assert_eq!(
713 vec![
714 dr::Operand::SourceLanguage(spirv::SourceLanguage::GLSL),
715 dr::Operand::LiteralBit32(450),
716 dr::Operand::IdRef(6),
717 dr::Operand::from("wow")
718 ],
719 inst.operands
720 );
721 }
722
723 #[test]
724 fn test_parsing_missing_one_optional_operand() {
725 let mut v = ZERO_BOUND_HEADER.to_vec();
726 v.append(&mut vec![0x03, 0x00, 0x04, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0xc2, 0x01, 0x00, 0x00]); v.append(&mut vec![0x06, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
731 {
732 let p = Parser::new(&v, &mut c);
733 assert_matches!(p.parse(), Ok(()));
734 }
735 assert_eq!(1, c.insts.len());
736 let inst = &c.insts[0];
737 assert_eq!("Source", inst.class.opname);
738 assert_eq!(None, inst.result_type);
739 assert_eq!(None, inst.result_id);
740 assert_eq!(
741 vec![
742 dr::Operand::SourceLanguage(spirv::SourceLanguage::GLSL),
743 dr::Operand::LiteralBit32(450),
744 dr::Operand::IdRef(6)
745 ],
746 inst.operands
747 );
748 }
749
750 #[test]
751 fn test_parsing_missing_two_optional_operands() {
752 let mut v = ZERO_BOUND_HEADER.to_vec();
753 v.append(&mut vec![0x03, 0x00, 0x03, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0xc2, 0x01, 0x00, 0x00]); let mut c = RetainingConsumer::new();
757 {
758 let p = Parser::new(&v, &mut c);
759 assert_matches!(p.parse(), Ok(()));
760 }
761 assert_eq!(1, c.insts.len());
762 let inst = &c.insts[0];
763 assert_eq!("Source", inst.class.opname);
764 assert_eq!(None, inst.result_type);
765 assert_eq!(None, inst.result_id);
766 assert_eq!(
767 vec![
768 dr::Operand::SourceLanguage(spirv::SourceLanguage::GLSL),
769 dr::Operand::LiteralBit32(450)
770 ],
771 inst.operands
772 );
773 }
774
775 #[derive(Debug)]
776 struct ErrorString(&'static str);
777 impl error::Error for ErrorString {}
778 impl fmt::Display for ErrorString {
779 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
780 let ErrorString(s) = self;
781 write!(f, "{}", s)
782 }
783 }
784
785 struct InitializeErrorConsumer;
786 impl Consumer for InitializeErrorConsumer {
787 fn initialize(&mut self) -> Action {
788 Action::Error(Box::new(ErrorString("init error")))
789 }
790 fn finalize(&mut self) -> Action {
791 Action::Continue
792 }
793 fn consume_header(&mut self, _: dr::ModuleHeader) -> Action {
794 Action::Continue
795 }
796 fn consume_instruction(&mut self, _: dr::Instruction) -> Action {
797 Action::Continue
798 }
799 }
800
801 #[test]
802 fn test_consumer_initialize_error() {
803 let v = vec![];
804 let mut c = InitializeErrorConsumer {};
805 let p = Parser::new(&v, &mut c);
806 let ret = p.parse();
807 assert_matches!(ret, Err(State::ConsumerError(_)));
808 assert_eq!(
809 "consumer error: init error",
810 format!("{}", ret.unwrap_err())
811 );
812 }
813
814 struct FinalizeErrorConsumer;
815 impl Consumer for FinalizeErrorConsumer {
816 fn initialize(&mut self) -> Action {
817 Action::Continue
818 }
819 fn finalize(&mut self) -> Action {
820 Action::Error(Box::new(ErrorString("fin error")))
821 }
822 fn consume_header(&mut self, _: dr::ModuleHeader) -> Action {
823 Action::Continue
824 }
825 fn consume_instruction(&mut self, _: dr::Instruction) -> Action {
826 Action::Continue
827 }
828 }
829
830 #[test]
831 fn test_consumer_finalize_error() {
832 let mut c = FinalizeErrorConsumer {};
833 let p = Parser::new(ZERO_BOUND_HEADER, &mut c);
834 let ret = p.parse();
835 assert_matches!(ret, Err(State::ConsumerError(_)));
836 assert_eq!("consumer error: fin error", format!("{}", ret.unwrap_err()));
837 }
838
839 struct ParseHeaderErrorConsumer;
840 impl Consumer for ParseHeaderErrorConsumer {
841 fn initialize(&mut self) -> Action {
842 Action::Continue
843 }
844 fn finalize(&mut self) -> Action {
845 Action::Continue
846 }
847 fn consume_header(&mut self, _: dr::ModuleHeader) -> Action {
848 Action::Error(Box::new(ErrorString("parse header error")))
849 }
850 fn consume_instruction(&mut self, _: dr::Instruction) -> Action {
851 Action::Continue
852 }
853 }
854
855 #[test]
856 fn test_consumer_parse_header_error() {
857 let mut c = ParseHeaderErrorConsumer {};
858 let p = Parser::new(ZERO_BOUND_HEADER, &mut c);
859 let ret = p.parse();
860 assert_matches!(ret, Err(State::ConsumerError(_)));
861 assert_eq!(
862 "consumer error: parse header error",
863 format!("{}", ret.unwrap_err())
864 );
865 }
866
867 struct ParseInstErrorConsumer;
868 impl Consumer for ParseInstErrorConsumer {
869 fn initialize(&mut self) -> Action {
870 Action::Continue
871 }
872 fn finalize(&mut self) -> Action {
873 Action::Continue
874 }
875 fn consume_header(&mut self, _: dr::ModuleHeader) -> Action {
876 Action::Continue
877 }
878 fn consume_instruction(&mut self, _: dr::Instruction) -> Action {
879 Action::Error(Box::new(ErrorString("parse inst error")))
880 }
881 }
882
883 #[test]
884 fn test_consumer_parse_inst_error() {
885 let mut b = ModuleBuilder::new();
886 b.inst(spirv::Op::Nop, vec![]);
887 let mut c = ParseInstErrorConsumer {};
888 let p = Parser::new(b.get(), &mut c);
889 let ret = p.parse();
890 assert_matches!(ret, Err(State::ConsumerError(_)));
891 assert_eq!(
892 "consumer error: parse inst error",
893 format!("{}", ret.unwrap_err())
894 );
895 }
896
897 #[test]
898 fn test_parsing_bit32_int() {
899 let mut v = ZERO_BOUND_HEADER.to_vec();
900 v.append(&mut vec![0x15, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x20, 0x00, 0x00, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x2b, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x12, 0x34, 0x56, 0x78]);
909 let mut c = RetainingConsumer::new();
910 {
911 let p = Parser::new(&v, &mut c);
912 assert_matches!(p.parse(), Ok(()));
913 }
914 assert_eq!(2, c.insts.len());
915 let inst = &c.insts[1];
916 assert_eq!("Constant", inst.class.opname);
917 assert_eq!(Some(1), inst.result_type);
918 assert_eq!(Some(2), inst.result_id);
919 assert_eq!(vec![dr::Operand::LiteralBit32(0x78563412)], inst.operands);
920 }
921
922 #[test]
923 fn test_parsing_bit64_int() {
924 let mut v = ZERO_BOUND_HEADER.to_vec();
925 v.append(&mut vec![0x15, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x40, 0x00, 0x00, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x2b, 0x00, 0x05, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x12, 0x34, 0x56, 0x78]);
934 v.append(&mut vec![0x90, 0xab, 0xcd, 0xef]);
935 let mut c = RetainingConsumer::new();
936 {
937 let p = Parser::new(&v, &mut c);
938 assert_matches!(p.parse(), Ok(()));
939 }
940 assert_eq!(2, c.insts.len());
941 let inst = &c.insts[1];
942 assert_eq!("Constant", inst.class.opname);
943 assert_eq!(Some(1), inst.result_type);
944 assert_eq!(Some(2), inst.result_id);
945 assert_eq!(
946 vec![dr::Operand::LiteralBit64(0xefcdab9078563412)],
947 inst.operands
948 );
949 }
950
951 #[test]
952 fn test_parsing_bit32_float() {
953 let mut v = ZERO_BOUND_HEADER.to_vec();
954 v.append(&mut vec![0x16, 0x00, 0x03, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x20, 0x00, 0x00, 0x00]); v.append(&mut vec![0x2b, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x14, 0xAE, 0x29, 0x42]); let mut c = RetainingConsumer::new();
963 {
964 let p = Parser::new(&v, &mut c);
965 assert_matches!(p.parse(), Ok(()));
966 }
967 assert_eq!(2, c.insts.len());
968 let inst = &c.insts[1];
969 assert_eq!("Constant", inst.class.opname);
970 assert_eq!(Some(1), inst.result_type);
971 assert_eq!(Some(2), inst.result_id);
972 assert_eq!(
973 vec![dr::Operand::LiteralBit32(42.42f32.to_bits())],
974 inst.operands
975 );
976 }
977
978 #[test]
979 fn test_parsing_bit64_float() {
980 let mut v = ZERO_BOUND_HEADER.to_vec();
981 v.append(&mut vec![0x16, 0x00, 0x03, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x40, 0x00, 0x00, 0x00]); v.append(&mut vec![0x2b, 0x00, 0x05, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0xAE, 0x47, 0xE1, 0x7A, 0x14, 0xAE, 0x28, 0xC0]); let mut c = RetainingConsumer::new();
990 {
991 let p = Parser::new(&v, &mut c);
992 assert_matches!(p.parse(), Ok(()));
993 }
994 assert_eq!(2, c.insts.len());
995 let inst = &c.insts[1];
996 assert_eq!("Constant", inst.class.opname);
997 assert_eq!(Some(1), inst.result_type);
998 assert_eq!(Some(2), inst.result_id);
999 assert_eq!(
1000 vec![dr::Operand::LiteralBit64((-12.34f64).to_bits())],
1001 inst.operands
1002 );
1003 }
1004
1005 #[test]
1006 fn test_parsing_spec_constant_op() {
1007 let mut v = ZERO_BOUND_HEADER.to_vec();
1008 v.append(&mut vec![0x34, 0x00, 0x05, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x7e, 0x00, 0x00, 0x00]); v.append(&mut vec![0x03, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1014 {
1015 let p = Parser::new(&v, &mut c);
1016 assert_matches!(p.parse(), Ok(()));
1017 }
1018 assert_eq!(1, c.insts.len());
1019 let inst = &c.insts[0];
1020 assert_eq!("SpecConstantOp", inst.class.opname);
1021 assert_eq!(Some(1), inst.result_type);
1022 assert_eq!(Some(2), inst.result_id);
1023 assert_eq!(
1024 vec![
1025 dr::Operand::LiteralSpecConstantOpInteger(spirv::Op::SNegate),
1026 dr::Operand::IdRef(3)
1027 ],
1028 inst.operands
1029 );
1030 }
1031
1032 #[test]
1033 fn test_parsing_spec_constant_op_missing_parameter() {
1034 let mut v = ZERO_BOUND_HEADER.to_vec();
1035 v.append(&mut vec![0x34, 0x00, 0x05, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x80, 0x00, 0x00, 0x00]); v.append(&mut vec![0x03, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1041 let p = Parser::new(&v, &mut c);
1042 assert_matches!(
1043 p.parse(),
1044 Err(State::OperandError(DecodeError::LimitReached(40)))
1047 );
1048 }
1049
1050 #[test]
1051 fn test_parsing_bitmasks_requiring_params_no_mem_access() {
1052 let mut v = ZERO_BOUND_HEADER.to_vec();
1053 v.append(&mut vec![0x3e, 0x00, 0x03, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1057 {
1058 let p = Parser::new(&v, &mut c);
1059 assert_matches!(p.parse(), Ok(()));
1060 }
1061 assert_eq!(1, c.insts.len());
1062 let inst = &c.insts[0];
1063 assert_eq!("Store", inst.class.opname);
1064 assert_eq!(None, inst.result_type);
1065 assert_eq!(None, inst.result_id);
1066 assert_eq!(
1067 vec![dr::Operand::IdRef(1), dr::Operand::IdRef(2)],
1068 inst.operands
1069 );
1070 }
1071 #[test]
1072 fn test_parsing_bitmasks_requiring_params_mem_access_no_param() {
1073 let mut v = ZERO_BOUND_HEADER.to_vec();
1074 v.append(&mut vec![0x3e, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1079 {
1080 let p = Parser::new(&v, &mut c);
1081 assert_matches!(p.parse(), Ok(()));
1082 }
1083 assert_eq!(1, c.insts.len());
1084 let inst = &c.insts[0];
1085 assert_eq!("Store", inst.class.opname);
1086 assert_eq!(None, inst.result_type);
1087 assert_eq!(None, inst.result_id);
1088 assert_eq!(
1089 vec![
1090 dr::Operand::IdRef(1),
1091 dr::Operand::IdRef(2),
1092 dr::Operand::MemoryAccess(spirv::MemoryAccess::VOLATILE)
1093 ],
1094 inst.operands
1095 );
1096 }
1097 #[test]
1098 fn test_parsing_bitmasks_requiring_params_mem_access_with_param() {
1099 let mut v = ZERO_BOUND_HEADER.to_vec();
1100 v.append(&mut vec![0x3e, 0x00, 0x05, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x03, 0x00, 0x00, 0x00]); v.append(&mut vec![0x04, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1106 {
1107 let p = Parser::new(&v, &mut c);
1108 assert_matches!(p.parse(), Ok(()));
1109 }
1110 assert_eq!(1, c.insts.len());
1111 let inst = &c.insts[0];
1112 assert_eq!("Store", inst.class.opname);
1113 assert_eq!(None, inst.result_type);
1114 assert_eq!(None, inst.result_id);
1115 assert_eq!(
1116 vec![
1117 dr::Operand::IdRef(1),
1118 dr::Operand::IdRef(2),
1119 dr::Operand::MemoryAccess(spirv::MemoryAccess::from_bits(3).unwrap()),
1120 dr::Operand::LiteralBit32(4)
1121 ],
1122 inst.operands
1123 );
1124 }
1125 #[test]
1126 fn test_parsing_bitmasks_requiring_params_mem_access_missing_param() {
1127 let mut v = ZERO_BOUND_HEADER.to_vec();
1128 v.append(&mut vec![0x3e, 0x00, 0x04, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x03, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1133 let p = Parser::new(&v, &mut c);
1134 assert_matches!(
1135 p.parse(),
1136 Err(State::OperandError(DecodeError::LimitReached(36)))
1139 );
1140 }
1141 #[test]
1142 fn test_parsing_bitmasks_requiring_params_img_operands_param_order() {
1143 let mut v = ZERO_BOUND_HEADER.to_vec();
1144 v.append(&mut vec![0x63, 0x00, 0x08, 0x00]); v.append(&mut vec![0x01, 0x00, 0x00, 0x00]); v.append(&mut vec![0x02, 0x00, 0x00, 0x00]); v.append(&mut vec![0x03, 0x00, 0x00, 0x00]); v.append(&mut vec![0x05, 0x00, 0x00, 0x00]); v.append(&mut vec![0xaa, 0x00, 0x00, 0x00]); v.append(&mut vec![0xbb, 0x00, 0x00, 0x00]); v.append(&mut vec![0xcc, 0x00, 0x00, 0x00]); let mut c = RetainingConsumer::new();
1153 {
1154 let p = Parser::new(&v, &mut c);
1155 assert_matches!(p.parse(), Ok(()));
1156 }
1157 assert_eq!(1, c.insts.len());
1158 let inst = &c.insts[0];
1159 assert_eq!("ImageWrite", inst.class.opname);
1160 assert_eq!(None, inst.result_type);
1161 assert_eq!(None, inst.result_id);
1162 assert_eq!(
1163 vec![
1164 dr::Operand::IdRef(1),
1165 dr::Operand::IdRef(2),
1166 dr::Operand::IdRef(3),
1167 dr::Operand::ImageOperands(spirv::ImageOperands::from_bits(5).unwrap()),
1168 dr::Operand::IdRef(0xaa),
1169 dr::Operand::IdRef(0xbb),
1170 dr::Operand::IdRef(0xcc)
1171 ],
1172 inst.operands
1173 );
1174 }
1175
1176 #[test]
1177 fn test_parse_words() {
1178 let words = vec![0x07230203, 0x01000000, 0, 0, 0, 0x00020011, 0x00000016];
1179 let mut c = RetainingConsumer::new();
1180 assert_matches!(parse_words(&words, &mut c), Ok(()));
1181 assert_eq!(1, c.insts.len());
1182 let inst = &c.insts[0];
1183 assert_eq!("Capability", inst.class.opname);
1184 assert_eq!(None, inst.result_type);
1185 assert_eq!(None, inst.result_id);
1186 assert_eq!(
1187 vec![dr::Operand::Capability(spirv::Capability::Int16)],
1188 inst.operands
1189 );
1190 }
1191}