1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
4 use spirv_parser::{IdRef, IdResult, Instruction};
5 use std::cell::RefCell;
6 use std::collections::HashMap;
9 use std::rc::{Rc, Weak};
11 pub(crate) trait GenericNode: Clone + fmt::Debug {
12 fn instructions(&self) -> &Vec<Instruction>;
13 fn to_node(this: Rc<Self>) -> Node;
14 fn label(&self) -> IdRef;
17 #[derive(Clone, Debug)]
18 pub(crate) struct SimpleNode {
19 pub(crate) label: IdRef,
20 pub(crate) instructions: Vec<Instruction>,
21 pub(crate) next: Node,
24 impl GenericNode for SimpleNode {
25 fn instructions(&self) -> &Vec<Instruction> {
28 fn to_node(this: Rc<Self>) -> Node {
31 fn label(&self) -> IdRef {
36 #[derive(Clone, Debug)]
37 pub(crate) struct SwitchDefault {
38 pub(crate) default_case: Node,
39 pub(crate) after_default_cases: Vec<Node>,
42 #[derive(Clone, Debug)]
43 pub(crate) struct SwitchNode {
44 pub(crate) label: IdRef,
45 pub(crate) instructions: Vec<Instruction>,
46 pub(crate) before_default_cases: Vec<Node>,
47 pub(crate) default: Option<SwitchDefault>,
48 pub(crate) next: Node,
51 impl GenericNode for SwitchNode {
52 fn instructions(&self) -> &Vec<Instruction> {
55 fn to_node(this: Rc<Self>) -> Node {
58 fn label(&self) -> IdRef {
63 #[derive(Clone, Debug)]
64 pub(crate) struct SwitchFallthroughNode {
65 pub(crate) label: IdRef,
66 pub(crate) instructions: Vec<Instruction>,
67 pub(crate) switch: RefCell<Weak<SwitchNode>>,
70 impl GenericNode for SwitchFallthroughNode {
71 fn instructions(&self) -> &Vec<Instruction> {
74 fn to_node(this: Rc<Self>) -> Node {
75 Node::SwitchFallthrough(this)
77 fn label(&self) -> IdRef {
82 #[derive(Clone, Debug)]
83 pub(crate) struct SwitchMergeNode {
84 pub(crate) label: IdRef,
85 pub(crate) instructions: Vec<Instruction>,
86 pub(crate) switch: RefCell<Weak<SwitchNode>>,
89 impl GenericNode for SwitchMergeNode {
90 fn instructions(&self) -> &Vec<Instruction> {
93 fn to_node(this: Rc<Self>) -> Node {
94 Node::SwitchMerge(this)
96 fn label(&self) -> IdRef {
101 #[derive(Clone, Debug)]
102 pub(crate) struct ConditionNode {
103 pub(crate) label: IdRef,
104 pub(crate) instructions: Vec<Instruction>,
105 pub(crate) true_node: Option<Node>,
106 pub(crate) false_node: Option<Node>,
107 pub(crate) next: Node,
110 impl GenericNode for ConditionNode {
111 fn instructions(&self) -> &Vec<Instruction> {
114 fn to_node(this: Rc<Self>) -> Node {
115 Node::Condition(this)
117 fn label(&self) -> IdRef {
122 #[derive(Clone, Debug)]
123 pub(crate) struct ConditionMergeNode {
124 pub(crate) label: IdRef,
125 pub(crate) instructions: Vec<Instruction>,
126 pub(crate) condition_node: RefCell<Weak<ConditionNode>>,
129 impl GenericNode for ConditionMergeNode {
130 fn instructions(&self) -> &Vec<Instruction> {
133 fn to_node(this: Rc<Self>) -> Node {
134 Node::ConditionMerge(this)
136 fn label(&self) -> IdRef {
141 #[derive(Clone, Debug)]
142 pub(crate) struct ReturnNode {
143 pub(crate) label: IdRef,
144 pub(crate) instructions: Vec<Instruction>,
147 impl GenericNode for ReturnNode {
148 fn instructions(&self) -> &Vec<Instruction> {
151 fn to_node(this: Rc<Self>) -> Node {
154 fn label(&self) -> IdRef {
159 #[derive(Clone, Debug)]
160 pub(crate) struct DiscardNode {
161 pub(crate) label: IdRef,
162 pub(crate) instructions: Vec<Instruction>,
165 impl GenericNode for DiscardNode {
166 fn instructions(&self) -> &Vec<Instruction> {
169 fn to_node(this: Rc<Self>) -> Node {
172 fn label(&self) -> IdRef {
177 #[derive(Clone, Debug)]
178 pub(crate) enum Node {
179 Simple(Rc<SimpleNode>),
180 Return(Rc<ReturnNode>),
181 Discard(Rc<DiscardNode>),
182 Switch(Rc<SwitchNode>),
183 SwitchFallthrough(Rc<SwitchFallthroughNode>),
184 SwitchMerge(Rc<SwitchMergeNode>),
185 Condition(Rc<ConditionNode>),
186 ConditionMerge(Rc<ConditionMergeNode>),
190 pub(crate) fn instructions(&self) -> &Vec<Instruction> {
192 Node::Simple(v) => v.instructions(),
193 Node::Return(v) => v.instructions(),
194 Node::Discard(v) => v.instructions(),
195 Node::Switch(v) => v.instructions(),
196 Node::SwitchFallthrough(v) => v.instructions(),
197 Node::SwitchMerge(v) => v.instructions(),
198 Node::Condition(v) => v.instructions(),
199 Node::ConditionMerge(v) => v.instructions(),
202 pub(crate) fn label(&self) -> IdRef {
204 Node::Simple(v) => v.label(),
205 Node::Return(v) => v.label(),
206 Node::Discard(v) => v.label(),
207 Node::Switch(v) => v.label(),
208 Node::SwitchFallthrough(v) => v.label(),
209 Node::SwitchMerge(v) => v.label(),
210 Node::Condition(v) => v.label(),
211 Node::ConditionMerge(v) => v.label(),
216 impl<T: GenericNode> From<Rc<T>> for Node {
217 fn from(v: Rc<T>) -> Node {
218 GenericNode::to_node(v)
222 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
223 enum SwitchCaseKind {
228 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
234 SwitchCase(SwitchCaseKind),
238 struct BasicBlock<'a> {
240 label_line_instructions: &'a [Instruction],
241 instructions: &'a [Instruction],
242 kind: RefCell<BlockKind>,
245 impl<'a> BasicBlock<'a> {
246 fn get_instructions(&self) -> Vec<Instruction> {
247 let mut retval: Vec<Instruction> =
248 Vec::with_capacity(self.label_line_instructions.len() + 1 + self.instructions.len());
249 retval.extend(self.label_line_instructions.iter().map(Clone::clone));
250 retval.push(Instruction::Label {
251 id_result: IdResult(self.label_id),
253 retval.extend(self.instructions.iter().map(Clone::clone));
256 fn set_kind(&self, kind: BlockKind) {
257 match self.kind.replace(kind) {
258 BlockKind::Unknown => {}
259 kind => unreachable!("block kind already set to {:?}", kind),
264 impl<'a> fmt::Debug for BasicBlock<'a> {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 write!(f, "BasicBlock:\n")?;
267 for instruction in self.get_instructions() {
268 write!(f, "{}", instruction)?;
274 struct ParseStateCondition {
275 merges: Vec<Rc<ConditionMergeNode>>,
279 struct ParseStateSwitch {
280 fallthrough: Option<Rc<SwitchFallthroughNode>>,
281 default_label: IdRef,
282 merges: Vec<Rc<SwitchMergeNode>>,
284 fallthrough_target: Option<IdRef>,
288 condition: Option<ParseStateCondition>,
289 switch: Option<ParseStateSwitch>,
292 fn get_basic_block<'a, 'b>(
293 basic_blocks: &'b HashMap<IdRef, BasicBlock<'a>>,
295 ) -> &'b BasicBlock<'a> {
298 .unwrap_or_else(|| unreachable!("label not found: {}", label_id))
302 fn push_condition(&mut self, condition: ParseStateCondition) -> Option<ParseStateCondition> {
303 mem::replace(&mut self.condition, Some(condition))
305 fn pop_condition(&mut self, old_condition: Option<ParseStateCondition>) -> ParseStateCondition {
306 mem::replace(&mut self.condition, old_condition).unwrap()
308 fn push_switch(&mut self, switch: ParseStateSwitch) -> Option<ParseStateSwitch> {
309 mem::replace(&mut self.switch, Some(switch))
311 fn pop_switch(&mut self, old_switch: Option<ParseStateSwitch>) -> ParseStateSwitch {
312 mem::replace(&mut self.switch, old_switch).unwrap()
314 fn get_switch(&mut self) -> &mut ParseStateSwitch {
315 self.switch.as_mut().unwrap()
319 basic_blocks: &HashMap<IdRef, BasicBlock>,
321 basic_block: &BasicBlock,
322 targets: &[(T, IdRef)],
323 default_label: IdRef,
326 get_basic_block(basic_blocks, merge_block).set_kind(BlockKind::SwitchMerge);
327 let mut last_target = None;
328 for &(_, target) in targets {
329 if Some(target) == last_target {
332 last_target = Some(target);
333 if target != merge_block {
334 get_basic_block(basic_blocks, target)
335 .set_kind(BlockKind::SwitchCase(SwitchCaseKind::Normal));
338 if default_label != merge_block {
339 get_basic_block(basic_blocks, default_label)
340 .set_kind(BlockKind::SwitchCase(SwitchCaseKind::Default));
342 let old_switch = self.push_switch(ParseStateSwitch {
343 default_label: default_label,
345 merge_label: merge_block,
347 fallthrough_target: None,
349 let default_node = if default_label != merge_block {
350 Some(self.parse(basic_blocks, default_label))
354 let mut default_fallthrough = self.get_switch().fallthrough.take();
355 let mut default_fallthrough_target = self.get_switch().fallthrough_target.take();
356 let mut cases = Vec::with_capacity(targets.len());
359 fallthrough: Option<Rc<SwitchFallthroughNode>>,
360 fallthrough_target: Option<IdRef>,
362 let mut last_target = None;
363 for (index, &(_, target)) in targets.iter().enumerate() {
364 if Some(target) == last_target {
367 last_target = Some(target);
368 let node = self.parse(basic_blocks, target);
369 let fallthrough_target = self.get_switch().fallthrough_target.take();
370 if let Some(fallthrough_target) = fallthrough_target {
371 if default_label != fallthrough_target {
373 Some(fallthrough_target),
374 targets.get(index + 1).map(|v| v.1),
375 "invalid fallthrough branch"
381 fallthrough: self.get_switch().fallthrough.take(),
385 let switch = self.pop_switch(old_switch);
386 let mut before_default_cases = None;
387 let mut output_cases = vec![];
388 let mut fallthroughs = vec![];
389 fallthroughs.extend(default_fallthrough);
397 ) in cases.into_iter().enumerate()
399 if Some(node.label()) == default_fallthrough_target {
400 if before_default_cases.is_none() {
401 before_default_cases = Some(mem::replace(&mut output_cases, vec![]));
403 assert!(output_cases.is_empty(), "invalid fallthrough branch");
406 output_cases.push(node);
407 fallthroughs.extend(fallthrough);
408 if Some(default_label) == fallthrough_target {
409 assert!(before_default_cases.is_none());
410 before_default_cases = Some(mem::replace(&mut output_cases, vec![]));
413 let before_default_cases =
414 before_default_cases.unwrap_or_else(|| mem::replace(&mut output_cases, vec![]));
415 let default = if let Some(default_node) = default_node {
417 default_case: default_node,
418 after_default_cases: output_cases,
423 let next = self.parse(basic_blocks, merge_block);
424 let retval = Rc::new(SwitchNode {
426 instructions: basic_block.get_instructions(),
427 before_default_cases,
431 for fallthrough in fallthroughs {
432 fallthrough.switch.replace(Rc::downgrade(&retval));
434 for merge in switch.merges {
435 merge.switch.replace(Rc::downgrade(&retval));
439 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
440 fn parse(&mut self, basic_blocks: &HashMap<IdRef, BasicBlock>, label_id: IdRef) -> Node {
441 let basic_block = get_basic_block(basic_blocks, label_id);
442 let (terminating_instruction, instructions_without_terminator) = basic_block
445 .expect("missing terminating instruction");
446 let control_header_instruction = instructions_without_terminator.last();
447 match (terminating_instruction, control_header_instruction) {
449 &Instruction::Branch { target_label },
450 Some(&Instruction::LoopMerge {
455 ) => unimplemented!(),
456 (&Instruction::Branch { target_label }, _) => {
457 let kind = *get_basic_block(basic_blocks, target_label).kind.borrow();
459 BlockKind::Unknown => {
460 let next = self.parse(basic_blocks, target_label);
463 instructions: basic_block.get_instructions(),
468 BlockKind::ConditionMerge => {
469 let mut condition = self
472 .expect("invalid branch to merge block");
474 target_label, condition.merge_label,
475 "invalid branch to merge block"
477 let retval = Rc::new(ConditionMergeNode {
479 instructions: basic_block.get_instructions(),
480 condition_node: Default::default(),
482 condition.merges.push(retval.clone());
485 BlockKind::LoopMerge => unimplemented!(),
486 BlockKind::LoopContinue => unimplemented!(),
487 BlockKind::SwitchCase(kind) => {
488 let mut switch = self.get_switch();
489 let retval = Rc::new(SwitchFallthroughNode {
491 instructions: basic_block.get_instructions(),
492 switch: Default::default(),
494 assert!(switch.fallthrough_target.is_none());
495 assert!(switch.fallthrough.is_none());
496 switch.fallthrough_target = Some(target_label);
497 switch.fallthrough = Some(retval.clone());
500 BlockKind::SwitchMerge => {
503 self.get_switch().merge_label,
504 "invalid branch to merge block"
506 let retval = Rc::new(SwitchMergeNode {
508 instructions: basic_block.get_instructions(),
509 switch: Default::default(),
511 self.get_switch().merges.push(retval.clone());
517 &Instruction::BranchConditional {
522 Some(&Instruction::LoopMerge {
527 ) => unimplemented!(),
529 &Instruction::BranchConditional {
534 Some(&Instruction::SelectionMerge { merge_block, .. }),
536 get_basic_block(basic_blocks, merge_block).set_kind(BlockKind::ConditionMerge);
537 let old_condition = self.push_condition(ParseStateCondition {
538 merge_label: merge_block,
541 let true_node = if true_label != merge_block {
542 Some(self.parse(basic_blocks, true_label))
546 let false_node = if false_label != merge_block {
547 Some(self.parse(basic_blocks, false_label))
551 let condition = self.pop_condition(old_condition);
552 let next = self.parse(basic_blocks, merge_block);
553 let retval = Rc::new(ConditionNode {
555 instructions: basic_block.get_instructions(),
560 for merge in condition.merges {
561 merge.condition_node.replace(Rc::downgrade(&retval));
565 (&Instruction::BranchConditional { .. }, _) => {
566 unreachable!("missing merge instruction")
569 &Instruction::Switch32 {
570 default: default_label,
574 Some(&Instruction::SelectionMerge { merge_block, .. }),
575 ) => self.parse_switch(
584 &Instruction::Switch64 {
585 default: default_label,
589 Some(&Instruction::SelectionMerge { merge_block, .. }),
590 ) => self.parse_switch(
598 (&Instruction::Switch32 { .. }, _) => unreachable!("missing merge instruction"),
599 (&Instruction::Switch64 { .. }, _) => unreachable!("missing merge instruction"),
600 (&Instruction::Kill {}, _) => Rc::new(DiscardNode {
602 instructions: basic_block.get_instructions(),
605 (&Instruction::Return {}, _) => Rc::new(ReturnNode {
607 instructions: basic_block.get_instructions(),
610 (&Instruction::ReturnValue { .. }, _) => Rc::new(ReturnNode {
612 instructions: basic_block.get_instructions(),
615 (&Instruction::Unreachable {}, _) => unimplemented!(),
617 "invalid basic block terminating instruction:\n{}",
618 terminating_instruction
624 pub(crate) fn create_cfg(mut input_instructions: &[Instruction]) -> Node {
625 let mut basic_blocks = HashMap::new();
626 let mut first_block = None;
627 'split_into_blocks: while !input_instructions.is_empty() {
628 let (label_id, label_line_instructions) = 'find_label: loop {
629 for (i, instruction) in input_instructions.iter().enumerate() {
631 Instruction::Label { id_result } => {
632 break 'find_label (id_result.0, &input_instructions[..i]);
634 Instruction::NoLine {} | Instruction::Line { .. } => {}
638 unreachable!("missing OpLabel")
640 if first_block.is_none() {
641 first_block = Some(label_id);
643 for i in 0..input_instructions.len() {
644 match &input_instructions[i] {
645 Instruction::Branch { .. }
646 | Instruction::BranchConditional { .. }
647 | Instruction::Switch32 { .. }
648 | Instruction::Switch64 { .. }
649 | Instruction::Kill { .. }
650 | Instruction::Return { .. }
651 | Instruction::ReturnValue { .. }
652 | Instruction::Unreachable { .. } => {
653 let (instructions, rest) = input_instructions.split_at(i + 1);
654 input_instructions = rest;
655 let previous = basic_blocks.insert(
658 label_line_instructions,
661 kind: RefCell::new(BlockKind::Unknown),
664 assert!(previous.is_none(), "duplicate OpLabel: {}", label_id);
665 continue 'split_into_blocks;
670 unreachable!("missing terminating instruction");
672 let first_block = first_block.expect("missing OpLabel");
677 .parse(&basic_blocks, first_block)
684 struct IdFactory(u32);
687 fn new() -> IdFactory {
690 fn next(&mut self) -> IdRef {
691 let retval = IdRef(self.0);
697 #[derive(Debug, Eq, PartialEq, Clone)]
698 enum SerializedCFGElement {
716 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>);
717 fn serialize_cfg_into_vec(&self) -> Vec<SerializedCFGElement> {
718 let mut retval = Vec::new();
719 self.serialize_cfg(&mut retval);
724 impl<T: SerializeCFG> SerializeCFG for Rc<T> {
725 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
726 (**self).serialize_cfg(output)
730 impl<'a, T: SerializeCFG> SerializeCFG for &'a T {
731 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
732 (**self).serialize_cfg(output)
736 impl SerializeCFG for SimpleNode {
737 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
738 output.push(SerializedCFGElement::Simple);
739 self.next.serialize_cfg(output)
743 impl SerializeCFG for ReturnNode {
744 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
745 output.push(SerializedCFGElement::Return);
749 impl SerializeCFG for DiscardNode {
750 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
751 output.push(SerializedCFGElement::Discard);
755 impl SerializeCFG for SwitchNode {
756 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
757 output.push(SerializedCFGElement::Switch);
758 for case in &self.before_default_cases {
759 output.push(SerializedCFGElement::SwitchCase);
760 case.serialize_cfg(output);
762 if let Some(default) = &self.default {
763 output.push(SerializedCFGElement::SwitchDefaultCase);
764 default.default_case.serialize_cfg(output);
765 for case in &default.after_default_cases {
766 output.push(SerializedCFGElement::SwitchCase);
767 case.serialize_cfg(output);
770 output.push(SerializedCFGElement::SwitchEnd);
771 self.next.serialize_cfg(output);
775 impl SerializeCFG for SwitchFallthroughNode {
776 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
777 output.push(SerializedCFGElement::SwitchFallthrough);
781 impl SerializeCFG for SwitchMergeNode {
782 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
783 output.push(SerializedCFGElement::SwitchMerge);
787 impl SerializeCFG for ConditionNode {
788 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
789 output.push(SerializedCFGElement::Condition);
790 if let Some(true_node) = &self.true_node {
791 output.push(SerializedCFGElement::ConditionTrue);
792 true_node.serialize_cfg(output);
794 if let Some(false_node) = &self.false_node {
795 output.push(SerializedCFGElement::ConditionFalse);
796 false_node.serialize_cfg(output);
798 output.push(SerializedCFGElement::ConditionEnd);
799 self.next.serialize_cfg(output)
803 impl SerializeCFG for ConditionMergeNode {
804 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
805 output.push(SerializedCFGElement::ConditionMerge);
809 impl SerializeCFG for Node {
810 fn serialize_cfg(&self, output: &mut Vec<SerializedCFGElement>) {
812 Node::Simple(v) => v.serialize_cfg(output),
813 Node::Return(v) => v.serialize_cfg(output),
814 Node::Discard(v) => v.serialize_cfg(output),
815 Node::Switch(v) => v.serialize_cfg(output),
816 Node::SwitchFallthrough(v) => v.serialize_cfg(output),
817 Node::SwitchMerge(v) => v.serialize_cfg(output),
818 Node::Condition(v) => v.serialize_cfg(output),
819 Node::ConditionMerge(v) => v.serialize_cfg(output),
824 fn test_cfg(instructions: &[Instruction], expected: &[SerializedCFGElement]) {
825 println!("instructions:");
826 for instruction in instructions {
827 print!("{}", instruction);
830 let cfg = create_cfg(&instructions);
831 assert_eq!(&*cfg.serialize_cfg_into_vec(), expected);
835 fn test_cfg_return() {
836 let mut id_factory = IdFactory::new();
837 let mut instructions = Vec::new();
839 let label1 = id_factory.next();
840 instructions.push(Instruction::NoLine);
841 instructions.push(Instruction::Label {
842 id_result: IdResult(label1),
844 instructions.push(Instruction::Return);
846 test_cfg(&instructions, &[SerializedCFGElement::Return]);
850 fn test_cfg_return_value() {
851 let mut id_factory = IdFactory::new();
852 let mut instructions = Vec::new();
854 let label1 = id_factory.next();
855 instructions.push(Instruction::NoLine);
856 instructions.push(Instruction::Label {
857 id_result: IdResult(label1),
859 instructions.push(Instruction::ReturnValue {
860 value: id_factory.next(),
863 test_cfg(&instructions, &[SerializedCFGElement::Return]);
867 fn test_cfg_simple_discard() {
868 let mut id_factory = IdFactory::new();
869 let mut instructions = Vec::new();
871 let label1 = id_factory.next();
872 let label2 = id_factory.next();
874 instructions.push(Instruction::NoLine);
875 instructions.push(Instruction::Label {
876 id_result: IdResult(label1),
878 instructions.push(Instruction::Branch {
879 target_label: label2,
882 instructions.push(Instruction::Label {
883 id_result: IdResult(label2),
885 instructions.push(Instruction::Kill);
889 &[SerializedCFGElement::Simple, SerializedCFGElement::Discard],
894 fn test_cfg_conditional_none_none() {
895 let mut id_factory = IdFactory::new();
896 let mut instructions = Vec::new();
898 let label_start = id_factory.next();
899 let label_endif = id_factory.next();
901 instructions.push(Instruction::NoLine);
902 instructions.push(Instruction::Label {
903 id_result: IdResult(label_start),
905 instructions.push(Instruction::SelectionMerge {
906 merge_block: label_endif,
907 selection_control: spirv_parser::SelectionControl::default(),
909 instructions.push(Instruction::BranchConditional {
910 condition: id_factory.next(),
911 true_label: label_endif,
912 false_label: label_endif,
913 branch_weights: vec![],
916 instructions.push(Instruction::Label {
917 id_result: IdResult(label_endif),
919 instructions.push(Instruction::Return);
924 SerializedCFGElement::Condition,
925 SerializedCFGElement::ConditionEnd,
926 SerializedCFGElement::Return,
932 fn test_cfg_conditional_merge_none() {
933 let mut id_factory = IdFactory::new();
934 let mut instructions = Vec::new();
936 let label_start = id_factory.next();
937 let label_then = id_factory.next();
938 let label_endif = id_factory.next();
940 instructions.push(Instruction::NoLine);
941 instructions.push(Instruction::Label {
942 id_result: IdResult(label_start),
944 instructions.push(Instruction::SelectionMerge {
945 merge_block: label_endif,
946 selection_control: spirv_parser::SelectionControl::default(),
948 instructions.push(Instruction::BranchConditional {
949 condition: id_factory.next(),
950 true_label: label_then,
951 false_label: label_endif,
952 branch_weights: vec![],
955 instructions.push(Instruction::Label {
956 id_result: IdResult(label_then),
958 instructions.push(Instruction::Branch {
959 target_label: label_endif,
962 instructions.push(Instruction::Label {
963 id_result: IdResult(label_endif),
965 instructions.push(Instruction::Return);
970 SerializedCFGElement::Condition,
971 SerializedCFGElement::ConditionTrue,
972 SerializedCFGElement::ConditionMerge,
973 SerializedCFGElement::ConditionEnd,
974 SerializedCFGElement::Return,
980 fn test_cfg_conditional_return_merge() {
981 let mut id_factory = IdFactory::new();
982 let mut instructions = Vec::new();
984 let label_start = id_factory.next();
985 let label_then = id_factory.next();
986 let label_else = id_factory.next();
987 let label_endif = id_factory.next();
989 instructions.push(Instruction::NoLine);
990 instructions.push(Instruction::Label {
991 id_result: IdResult(label_start),
993 instructions.push(Instruction::SelectionMerge {
994 merge_block: label_endif,
995 selection_control: spirv_parser::SelectionControl::default(),
997 instructions.push(Instruction::BranchConditional {
998 condition: id_factory.next(),
999 true_label: label_then,
1000 false_label: label_else,
1001 branch_weights: vec![],
1004 instructions.push(Instruction::Label {
1005 id_result: IdResult(label_then),
1007 instructions.push(Instruction::Return);
1009 instructions.push(Instruction::Label {
1010 id_result: IdResult(label_else),
1012 instructions.push(Instruction::Branch {
1013 target_label: label_endif,
1016 instructions.push(Instruction::Label {
1017 id_result: IdResult(label_endif),
1019 instructions.push(Instruction::Return);
1024 SerializedCFGElement::Condition,
1025 SerializedCFGElement::ConditionTrue,
1026 SerializedCFGElement::Return,
1027 SerializedCFGElement::ConditionFalse,
1028 SerializedCFGElement::ConditionMerge,
1029 SerializedCFGElement::ConditionEnd,
1030 SerializedCFGElement::Return,
1036 fn test_cfg_switch_default_break() {
1037 let mut id_factory = IdFactory::new();
1038 let mut instructions = Vec::new();
1040 let label_start = id_factory.next();
1041 let label_default = id_factory.next();
1042 let label_merge = id_factory.next();
1044 instructions.push(Instruction::NoLine);
1045 instructions.push(Instruction::Label {
1046 id_result: IdResult(label_start),
1048 instructions.push(Instruction::SelectionMerge {
1049 merge_block: label_merge,
1050 selection_control: spirv_parser::SelectionControl::default(),
1052 instructions.push(Instruction::Switch64 {
1053 selector: id_factory.next(),
1054 default: label_default,
1058 instructions.push(Instruction::Label {
1059 id_result: IdResult(label_default),
1061 instructions.push(Instruction::Branch {
1062 target_label: label_merge,
1065 instructions.push(Instruction::Label {
1066 id_result: IdResult(label_merge),
1068 instructions.push(Instruction::Return);
1073 SerializedCFGElement::Switch,
1074 SerializedCFGElement::SwitchDefaultCase,
1075 SerializedCFGElement::SwitchMerge,
1076 SerializedCFGElement::SwitchEnd,
1077 SerializedCFGElement::Return,
1083 fn test_cfg_switch_return_default_break() {
1084 let mut id_factory = IdFactory::new();
1085 let mut instructions = Vec::new();
1087 let label_start = id_factory.next();
1088 let label_case1 = id_factory.next();
1089 let label_default = id_factory.next();
1090 let label_merge = id_factory.next();
1092 instructions.push(Instruction::NoLine);
1093 instructions.push(Instruction::Label {
1094 id_result: IdResult(label_start),
1096 instructions.push(Instruction::SelectionMerge {
1097 merge_block: label_merge,
1098 selection_control: spirv_parser::SelectionControl::default(),
1100 instructions.push(Instruction::Switch64 {
1101 selector: id_factory.next(),
1102 default: label_default,
1103 target: vec![(0, label_case1)],
1106 instructions.push(Instruction::Label {
1107 id_result: IdResult(label_case1),
1109 instructions.push(Instruction::Return);
1111 instructions.push(Instruction::Label {
1112 id_result: IdResult(label_default),
1114 instructions.push(Instruction::Branch {
1115 target_label: label_merge,
1118 instructions.push(Instruction::Label {
1119 id_result: IdResult(label_merge),
1121 instructions.push(Instruction::Return);
1126 SerializedCFGElement::Switch,
1127 SerializedCFGElement::SwitchCase,
1128 SerializedCFGElement::Return,
1129 SerializedCFGElement::SwitchDefaultCase,
1130 SerializedCFGElement::SwitchMerge,
1131 SerializedCFGElement::SwitchEnd,
1132 SerializedCFGElement::Return,
1138 fn test_cfg_switch_fallthrough_default_break() {
1139 let mut id_factory = IdFactory::new();
1140 let mut instructions = Vec::new();
1142 let label_start = id_factory.next();
1143 let label_case1 = id_factory.next();
1144 let label_default = id_factory.next();
1145 let label_merge = id_factory.next();
1147 instructions.push(Instruction::NoLine);
1148 instructions.push(Instruction::Label {
1149 id_result: IdResult(label_start),
1151 instructions.push(Instruction::SelectionMerge {
1152 merge_block: label_merge,
1153 selection_control: spirv_parser::SelectionControl::default(),
1155 instructions.push(Instruction::Switch64 {
1156 selector: id_factory.next(),
1157 default: label_default,
1158 target: vec![(0, label_case1)],
1161 instructions.push(Instruction::Label {
1162 id_result: IdResult(label_case1),
1164 instructions.push(Instruction::Branch {
1165 target_label: label_default,
1168 instructions.push(Instruction::Label {
1169 id_result: IdResult(label_default),
1171 instructions.push(Instruction::Branch {
1172 target_label: label_merge,
1175 instructions.push(Instruction::Label {
1176 id_result: IdResult(label_merge),
1178 instructions.push(Instruction::Return);
1183 SerializedCFGElement::Switch,
1184 SerializedCFGElement::SwitchCase,
1185 SerializedCFGElement::SwitchFallthrough,
1186 SerializedCFGElement::SwitchDefaultCase,
1187 SerializedCFGElement::SwitchMerge,
1188 SerializedCFGElement::SwitchEnd,
1189 SerializedCFGElement::Return,
1195 fn test_cfg_switch_fallthrough_default_fallthrough_break() {
1196 let mut id_factory = IdFactory::new();
1197 let mut instructions = Vec::new();
1199 let label_start = id_factory.next();
1200 let label_case1 = id_factory.next();
1201 let label_default = id_factory.next();
1202 let label_case2 = id_factory.next();
1203 let label_merge = id_factory.next();
1205 instructions.push(Instruction::NoLine);
1206 instructions.push(Instruction::Label {
1207 id_result: IdResult(label_start),
1209 instructions.push(Instruction::SelectionMerge {
1210 merge_block: label_merge,
1211 selection_control: spirv_parser::SelectionControl::default(),
1213 instructions.push(Instruction::Switch64 {
1214 selector: id_factory.next(),
1215 default: label_default,
1216 target: vec![(0, label_case1), (1, label_case1), (2, label_case2)],
1219 instructions.push(Instruction::Label {
1220 id_result: IdResult(label_case1),
1222 instructions.push(Instruction::Branch {
1223 target_label: label_default,
1226 instructions.push(Instruction::Label {
1227 id_result: IdResult(label_default),
1229 instructions.push(Instruction::Branch {
1230 target_label: label_case2,
1233 instructions.push(Instruction::Label {
1234 id_result: IdResult(label_case2),
1236 instructions.push(Instruction::Branch {
1237 target_label: label_merge,
1240 instructions.push(Instruction::Label {
1241 id_result: IdResult(label_merge),
1243 instructions.push(Instruction::Return);
1248 SerializedCFGElement::Switch,
1249 SerializedCFGElement::SwitchCase,
1250 SerializedCFGElement::SwitchFallthrough,
1251 SerializedCFGElement::SwitchDefaultCase,
1252 SerializedCFGElement::SwitchFallthrough,
1253 SerializedCFGElement::SwitchCase,
1254 SerializedCFGElement::SwitchMerge,
1255 SerializedCFGElement::SwitchEnd,
1256 SerializedCFGElement::Return,
1262 fn test_cfg_switch_break_default_fallthrough_break() {
1263 let mut id_factory = IdFactory::new();
1264 let mut instructions = Vec::new();
1266 let label_start = id_factory.next();
1267 let label_case1 = id_factory.next();
1268 let label_default = id_factory.next();
1269 let label_case2 = id_factory.next();
1270 let label_merge = id_factory.next();
1272 instructions.push(Instruction::NoLine);
1273 instructions.push(Instruction::Label {
1274 id_result: IdResult(label_start),
1276 instructions.push(Instruction::SelectionMerge {
1277 merge_block: label_merge,
1278 selection_control: spirv_parser::SelectionControl::default(),
1280 instructions.push(Instruction::Switch32 {
1281 selector: id_factory.next(),
1282 default: label_default,
1283 target: vec![(0, label_case1), (1, label_case1), (2, label_case2)],
1286 instructions.push(Instruction::Label {
1287 id_result: IdResult(label_case1),
1289 instructions.push(Instruction::Branch {
1290 target_label: label_merge,
1293 instructions.push(Instruction::Label {
1294 id_result: IdResult(label_default),
1296 instructions.push(Instruction::Branch {
1297 target_label: label_case2,
1300 instructions.push(Instruction::Label {
1301 id_result: IdResult(label_case2),
1303 instructions.push(Instruction::Branch {
1304 target_label: label_merge,
1307 instructions.push(Instruction::Label {
1308 id_result: IdResult(label_merge),
1310 instructions.push(Instruction::Return);
1315 SerializedCFGElement::Switch,
1316 SerializedCFGElement::SwitchCase,
1317 SerializedCFGElement::SwitchMerge,
1318 SerializedCFGElement::SwitchDefaultCase,
1319 SerializedCFGElement::SwitchFallthrough,
1320 SerializedCFGElement::SwitchCase,
1321 SerializedCFGElement::SwitchMerge,
1322 SerializedCFGElement::SwitchEnd,
1323 SerializedCFGElement::Return,