1use crate::context::{BlockId, TypeId, ValueRef};
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub struct IntArithFlags {
12 pub nuw: bool,
14 pub nsw: bool,
16}
17
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20pub struct ExactFlag {
21 pub exact: bool,
23}
24
25#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
27pub struct FastMathFlags {
28 pub nnan: bool,
30 pub ninf: bool,
32 pub nsz: bool,
34 pub arcp: bool,
36 pub contract: bool,
38 pub afn: bool,
40 pub reassoc: bool,
42 pub fast: bool,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum IntPredicate {
53 Eq,
55 Ne,
57 Ugt,
59 Uge,
61 Ult,
63 Ule,
65 Sgt,
67 Sge,
69 Slt,
71 Sle,
73}
74
75impl IntPredicate {
76 pub fn as_str(self) -> &'static str {
78 match self {
79 IntPredicate::Eq => "eq",
80 IntPredicate::Ne => "ne",
81 IntPredicate::Ugt => "ugt",
82 IntPredicate::Uge => "uge",
83 IntPredicate::Ult => "ult",
84 IntPredicate::Ule => "ule",
85 IntPredicate::Sgt => "sgt",
86 IntPredicate::Sge => "sge",
87 IntPredicate::Slt => "slt",
88 IntPredicate::Sle => "sle",
89 }
90 }
91}
92
93#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum FloatPredicate {
96 False,
98 Oeq,
100 Ogt,
102 Oge,
104 Olt,
106 Ole,
108 One,
110 Ord,
112 Uno,
114 Ueq,
116 Ugt,
118 Uge,
120 Ult,
122 Ule,
124 Une,
126 True,
128}
129
130impl FloatPredicate {
131 pub fn as_str(self) -> &'static str {
133 match self {
134 FloatPredicate::False => "false",
135 FloatPredicate::Oeq => "oeq",
136 FloatPredicate::Ogt => "ogt",
137 FloatPredicate::Oge => "oge",
138 FloatPredicate::Olt => "olt",
139 FloatPredicate::Ole => "ole",
140 FloatPredicate::One => "one",
141 FloatPredicate::Ord => "ord",
142 FloatPredicate::Uno => "uno",
143 FloatPredicate::Ueq => "ueq",
144 FloatPredicate::Ugt => "ugt",
145 FloatPredicate::Uge => "uge",
146 FloatPredicate::Ult => "ult",
147 FloatPredicate::Ule => "ule",
148 FloatPredicate::Une => "une",
149 FloatPredicate::True => "true",
150 }
151 }
152}
153
154#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156pub enum TailCallKind {
157 None,
159 Tail,
161 MustTail,
163 NoTail,
165}
166
167#[derive(Clone, Debug, PartialEq)]
173pub enum InstrKind {
174 Add {
177 flags: IntArithFlags,
178 lhs: ValueRef,
179 rhs: ValueRef,
180 },
181 Sub {
183 flags: IntArithFlags,
184 lhs: ValueRef,
185 rhs: ValueRef,
186 },
187 Mul {
189 flags: IntArithFlags,
190 lhs: ValueRef,
191 rhs: ValueRef,
192 },
193 UDiv {
195 exact: bool,
196 lhs: ValueRef,
197 rhs: ValueRef,
198 },
199 SDiv {
201 exact: bool,
202 lhs: ValueRef,
203 rhs: ValueRef,
204 },
205 URem {
207 lhs: ValueRef,
208 rhs: ValueRef,
209 },
210 SRem {
212 lhs: ValueRef,
213 rhs: ValueRef,
214 },
215
216 And {
219 lhs: ValueRef,
220 rhs: ValueRef,
221 },
222 Or {
224 lhs: ValueRef,
225 rhs: ValueRef,
226 },
227 Xor {
229 lhs: ValueRef,
230 rhs: ValueRef,
231 },
232 Shl {
234 flags: IntArithFlags,
235 lhs: ValueRef,
236 rhs: ValueRef,
237 },
238 LShr {
240 exact: bool,
241 lhs: ValueRef,
242 rhs: ValueRef,
243 },
244 AShr {
246 exact: bool,
247 lhs: ValueRef,
248 rhs: ValueRef,
249 },
250
251 FAdd {
254 flags: FastMathFlags,
255 lhs: ValueRef,
256 rhs: ValueRef,
257 },
258 FSub {
260 flags: FastMathFlags,
261 lhs: ValueRef,
262 rhs: ValueRef,
263 },
264 FMul {
266 flags: FastMathFlags,
267 lhs: ValueRef,
268 rhs: ValueRef,
269 },
270 FDiv {
272 flags: FastMathFlags,
273 lhs: ValueRef,
274 rhs: ValueRef,
275 },
276 FRem {
278 flags: FastMathFlags,
279 lhs: ValueRef,
280 rhs: ValueRef,
281 },
282 FNeg {
284 flags: FastMathFlags,
285 operand: ValueRef,
286 },
287
288 ICmp {
291 pred: IntPredicate,
292 lhs: ValueRef,
293 rhs: ValueRef,
294 },
295 FCmp {
297 flags: FastMathFlags,
298 pred: FloatPredicate,
299 lhs: ValueRef,
300 rhs: ValueRef,
301 },
302
303 Alloca {
306 alloc_ty: TypeId,
307 num_elements: Option<ValueRef>,
308 align: Option<u32>,
309 },
310 Load {
312 ty: TypeId,
313 ptr: ValueRef,
314 align: Option<u32>,
315 volatile: bool,
316 },
317 Store {
319 val: ValueRef,
320 ptr: ValueRef,
321 align: Option<u32>,
322 volatile: bool,
323 },
324 GetElementPtr {
326 inbounds: bool,
327 base_ty: TypeId,
328 ptr: ValueRef,
329 indices: Vec<ValueRef>,
330 },
331
332 Trunc {
335 val: ValueRef,
336 to: TypeId,
337 },
338 ZExt {
340 val: ValueRef,
341 to: TypeId,
342 },
343 SExt {
345 val: ValueRef,
346 to: TypeId,
347 },
348 FPTrunc {
350 val: ValueRef,
351 to: TypeId,
352 },
353 FPExt {
355 val: ValueRef,
356 to: TypeId,
357 },
358 FPToUI {
360 val: ValueRef,
361 to: TypeId,
362 },
363 FPToSI {
365 val: ValueRef,
366 to: TypeId,
367 },
368 UIToFP {
370 val: ValueRef,
371 to: TypeId,
372 },
373 SIToFP {
375 val: ValueRef,
376 to: TypeId,
377 },
378 PtrToInt {
380 val: ValueRef,
381 to: TypeId,
382 },
383 IntToPtr {
385 val: ValueRef,
386 to: TypeId,
387 },
388 BitCast {
390 val: ValueRef,
391 to: TypeId,
392 },
393 AddrSpaceCast {
395 val: ValueRef,
396 to: TypeId,
397 },
398 Freeze {
400 val: ValueRef,
401 },
402
403 Select {
406 cond: ValueRef,
407 then_val: ValueRef,
408 else_val: ValueRef,
409 },
410 Phi {
412 ty: TypeId,
413 incoming: Vec<(ValueRef, BlockId)>,
414 },
415 ExtractValue {
417 aggregate: ValueRef,
418 indices: Vec<u32>,
419 },
420 InsertValue {
422 aggregate: ValueRef,
423 val: ValueRef,
424 indices: Vec<u32>,
425 },
426 ExtractElement {
428 vec: ValueRef,
429 idx: ValueRef,
430 },
431 InsertElement {
433 vec: ValueRef,
434 val: ValueRef,
435 idx: ValueRef,
436 },
437 ShuffleVector {
439 v1: ValueRef,
440 v2: ValueRef,
441 mask: Vec<i32>,
442 },
443
444 Call {
447 tail: TailCallKind,
448 callee_ty: TypeId,
449 callee: ValueRef,
450 args: Vec<ValueRef>,
451 },
452
453 Ret {
456 val: Option<ValueRef>,
457 },
458 Br {
460 dest: BlockId,
461 },
462 CondBr {
464 cond: ValueRef,
465 then_dest: BlockId,
466 else_dest: BlockId,
467 },
468 Switch {
470 val: ValueRef,
471 default: BlockId,
472 cases: Vec<(ValueRef, BlockId)>,
473 },
474 Unreachable,
476}
477
478impl InstrKind {
479 pub fn is_terminator(&self) -> bool {
481 matches!(
482 self,
483 InstrKind::Ret { .. }
484 | InstrKind::Br { .. }
485 | InstrKind::CondBr { .. }
486 | InstrKind::Switch { .. }
487 | InstrKind::Unreachable
488 )
489 }
490
491 pub fn opcode(&self) -> &'static str {
493 match self {
494 InstrKind::Add { .. } => "add",
495 InstrKind::Sub { .. } => "sub",
496 InstrKind::Mul { .. } => "mul",
497 InstrKind::UDiv { .. } => "udiv",
498 InstrKind::SDiv { .. } => "sdiv",
499 InstrKind::URem { .. } => "urem",
500 InstrKind::SRem { .. } => "srem",
501 InstrKind::And { .. } => "and",
502 InstrKind::Or { .. } => "or",
503 InstrKind::Xor { .. } => "xor",
504 InstrKind::Shl { .. } => "shl",
505 InstrKind::LShr { .. } => "lshr",
506 InstrKind::AShr { .. } => "ashr",
507 InstrKind::FAdd { .. } => "fadd",
508 InstrKind::FSub { .. } => "fsub",
509 InstrKind::FMul { .. } => "fmul",
510 InstrKind::FDiv { .. } => "fdiv",
511 InstrKind::FRem { .. } => "frem",
512 InstrKind::FNeg { .. } => "fneg",
513 InstrKind::ICmp { .. } => "icmp",
514 InstrKind::FCmp { .. } => "fcmp",
515 InstrKind::Alloca { .. } => "alloca",
516 InstrKind::Load { .. } => "load",
517 InstrKind::Store { .. } => "store",
518 InstrKind::GetElementPtr { .. } => "getelementptr",
519 InstrKind::Trunc { .. } => "trunc",
520 InstrKind::ZExt { .. } => "zext",
521 InstrKind::SExt { .. } => "sext",
522 InstrKind::FPTrunc { .. } => "fptrunc",
523 InstrKind::FPExt { .. } => "fpext",
524 InstrKind::FPToUI { .. } => "fptoui",
525 InstrKind::FPToSI { .. } => "fptosi",
526 InstrKind::UIToFP { .. } => "uitofp",
527 InstrKind::SIToFP { .. } => "sitofp",
528 InstrKind::PtrToInt { .. } => "ptrtoint",
529 InstrKind::IntToPtr { .. } => "inttoptr",
530 InstrKind::BitCast { .. } => "bitcast",
531 InstrKind::AddrSpaceCast { .. } => "addrspacecast",
532 InstrKind::Freeze { .. } => "freeze",
533 InstrKind::Select { .. } => "select",
534 InstrKind::Phi { .. } => "phi",
535 InstrKind::ExtractValue { .. } => "extractvalue",
536 InstrKind::InsertValue { .. } => "insertvalue",
537 InstrKind::ExtractElement { .. } => "extractelement",
538 InstrKind::InsertElement { .. } => "insertelement",
539 InstrKind::ShuffleVector { .. } => "shufflevector",
540 InstrKind::Call { .. } => "call",
541 InstrKind::Ret { .. } => "ret",
542 InstrKind::Br { .. } => "br",
543 InstrKind::CondBr { .. } => "br",
544 InstrKind::Switch { .. } => "switch",
545 InstrKind::Unreachable => "unreachable",
546 }
547 }
548
549 pub fn operands(&self) -> Vec<ValueRef> {
551 match self {
552 InstrKind::Add { lhs, rhs, .. }
553 | InstrKind::Sub { lhs, rhs, .. }
554 | InstrKind::Mul { lhs, rhs, .. }
555 | InstrKind::UDiv { lhs, rhs, .. }
556 | InstrKind::SDiv { lhs, rhs, .. }
557 | InstrKind::URem { lhs, rhs }
558 | InstrKind::SRem { lhs, rhs }
559 | InstrKind::And { lhs, rhs }
560 | InstrKind::Or { lhs, rhs }
561 | InstrKind::Xor { lhs, rhs }
562 | InstrKind::Shl { lhs, rhs, .. }
563 | InstrKind::LShr { lhs, rhs, .. }
564 | InstrKind::AShr { lhs, rhs, .. }
565 | InstrKind::FAdd { lhs, rhs, .. }
566 | InstrKind::FSub { lhs, rhs, .. }
567 | InstrKind::FMul { lhs, rhs, .. }
568 | InstrKind::FDiv { lhs, rhs, .. }
569 | InstrKind::FRem { lhs, rhs, .. }
570 | InstrKind::ICmp { lhs, rhs, .. }
571 | InstrKind::FCmp { lhs, rhs, .. } => vec![*lhs, *rhs],
572
573 InstrKind::FNeg { operand, .. } => vec![*operand],
574
575 InstrKind::Alloca { num_elements, .. } => num_elements.iter().copied().collect(),
576 InstrKind::Load { ptr, .. } => vec![*ptr],
577 InstrKind::Store { val, ptr, .. } => vec![*val, *ptr],
578 InstrKind::GetElementPtr { ptr, indices, .. } => {
579 let mut v = vec![*ptr];
580 v.extend_from_slice(indices);
581 v
582 }
583
584 InstrKind::Trunc { val, .. }
585 | InstrKind::ZExt { val, .. }
586 | InstrKind::SExt { val, .. }
587 | InstrKind::FPTrunc { val, .. }
588 | InstrKind::FPExt { val, .. }
589 | InstrKind::FPToUI { val, .. }
590 | InstrKind::FPToSI { val, .. }
591 | InstrKind::UIToFP { val, .. }
592 | InstrKind::SIToFP { val, .. }
593 | InstrKind::PtrToInt { val, .. }
594 | InstrKind::IntToPtr { val, .. }
595 | InstrKind::BitCast { val, .. }
596 | InstrKind::AddrSpaceCast { val, .. }
597 | InstrKind::Freeze { val } => vec![*val],
598
599 InstrKind::Select {
600 cond,
601 then_val,
602 else_val,
603 } => {
604 vec![*cond, *then_val, *else_val]
605 }
606 InstrKind::Phi { incoming, .. } => incoming.iter().map(|(v, _)| *v).collect(),
607 InstrKind::ExtractValue { aggregate, .. } => vec![*aggregate],
608 InstrKind::InsertValue { aggregate, val, .. } => vec![*aggregate, *val],
609 InstrKind::ExtractElement { vec, idx } => vec![*vec, *idx],
610 InstrKind::InsertElement { vec, val, idx } => vec![*vec, *val, *idx],
611 InstrKind::ShuffleVector { v1, v2, .. } => vec![*v1, *v2],
612 InstrKind::Call { callee, args, .. } => {
613 let mut v = vec![*callee];
614 v.extend_from_slice(args);
615 v
616 }
617 InstrKind::Ret { val } => val.iter().copied().collect(),
618 InstrKind::Br { .. } | InstrKind::Unreachable => vec![],
619 InstrKind::CondBr { cond, .. } => vec![*cond],
620 InstrKind::Switch { val, cases, .. } => {
621 let mut v = vec![*val];
622 for (case_val, _) in cases {
623 v.push(*case_val);
624 }
625 v
626 }
627 }
628 }
629
630 pub fn successors(&self) -> Vec<BlockId> {
636 match self {
637 InstrKind::Br { dest } => vec![*dest],
638 InstrKind::CondBr {
639 then_dest,
640 else_dest,
641 ..
642 } => {
643 vec![*then_dest, *else_dest]
644 }
645 InstrKind::Switch { default, cases, .. } => {
646 let mut v = vec![*default];
647 for (_, bb) in cases {
648 v.push(*bb);
649 }
650 v
651 }
652 InstrKind::Ret { .. }
656 | InstrKind::Unreachable
657 | InstrKind::Add { .. }
658 | InstrKind::Sub { .. }
659 | InstrKind::Mul { .. }
660 | InstrKind::UDiv { .. }
661 | InstrKind::SDiv { .. }
662 | InstrKind::URem { .. }
663 | InstrKind::SRem { .. }
664 | InstrKind::And { .. }
665 | InstrKind::Or { .. }
666 | InstrKind::Xor { .. }
667 | InstrKind::Shl { .. }
668 | InstrKind::LShr { .. }
669 | InstrKind::AShr { .. }
670 | InstrKind::FAdd { .. }
671 | InstrKind::FSub { .. }
672 | InstrKind::FMul { .. }
673 | InstrKind::FDiv { .. }
674 | InstrKind::FRem { .. }
675 | InstrKind::FNeg { .. }
676 | InstrKind::ICmp { .. }
677 | InstrKind::FCmp { .. }
678 | InstrKind::Alloca { .. }
679 | InstrKind::Load { .. }
680 | InstrKind::Store { .. }
681 | InstrKind::GetElementPtr { .. }
682 | InstrKind::Trunc { .. }
683 | InstrKind::ZExt { .. }
684 | InstrKind::SExt { .. }
685 | InstrKind::FPTrunc { .. }
686 | InstrKind::FPExt { .. }
687 | InstrKind::FPToUI { .. }
688 | InstrKind::FPToSI { .. }
689 | InstrKind::UIToFP { .. }
690 | InstrKind::SIToFP { .. }
691 | InstrKind::PtrToInt { .. }
692 | InstrKind::IntToPtr { .. }
693 | InstrKind::BitCast { .. }
694 | InstrKind::AddrSpaceCast { .. }
695 | InstrKind::Freeze { .. }
696 | InstrKind::Select { .. }
697 | InstrKind::Phi { .. }
698 | InstrKind::ExtractValue { .. }
699 | InstrKind::InsertValue { .. }
700 | InstrKind::ExtractElement { .. }
701 | InstrKind::InsertElement { .. }
702 | InstrKind::ShuffleVector { .. }
703 | InstrKind::Call { .. } => vec![],
704 }
705 }
706}
707
708#[derive(Clone, Debug)]
710pub struct Instruction {
711 pub name: Option<String>,
713 pub ty: TypeId,
715 pub kind: InstrKind,
717}
718
719impl Instruction {
720 pub fn new(name: Option<String>, ty: TypeId, kind: InstrKind) -> Self {
722 Instruction { name, ty, kind }
723 }
724
725 pub fn is_terminator(&self) -> bool {
727 self.kind.is_terminator()
728 }
729
730 pub fn operands(&self) -> Vec<ValueRef> {
732 self.kind.operands()
733 }
734
735 pub fn successors(&self) -> Vec<BlockId> {
737 self.kind.successors()
738 }
739}
740
741#[cfg(test)]
742mod tests {
743 use super::*;
744 use crate::context::{BlockId, ConstId, Context, InstrId};
745
746 fn c0() -> ValueRef { ValueRef::Constant(ConstId(0)) }
748 fn c1() -> ValueRef { ValueRef::Constant(ConstId(1)) }
749 fn c2() -> ValueRef { ValueRef::Constant(ConstId(2)) }
750 fn v0() -> ValueRef { ValueRef::Instruction(InstrId(0)) }
751 fn b0() -> BlockId { BlockId(0) }
752 fn b1() -> BlockId { BlockId(1) }
753
754 #[test]
757 fn terminator_check() {
758 let _ctx = Context::new();
759 let ret = InstrKind::Ret { val: None };
760 assert!(ret.is_terminator());
761 let add = InstrKind::Add {
762 flags: IntArithFlags::default(),
763 lhs: c0(),
764 rhs: c0(),
765 };
766 assert!(!add.is_terminator());
767 }
768
769 #[test]
770 fn opcode_names() {
771 assert_eq!(InstrKind::Unreachable.opcode(), "unreachable");
772 let br = InstrKind::Br { dest: b0() };
773 assert_eq!(br.opcode(), "br");
774 }
775
776 #[test]
779 fn operands_add() {
780 let k = InstrKind::Add { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() };
781 assert_eq!(k.operands(), vec![c0(), c1()]);
782 }
783
784 #[test]
785 fn operands_sub() {
786 let k = InstrKind::Sub { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() };
787 assert_eq!(k.operands(), vec![c0(), c1()]);
788 }
789
790 #[test]
791 fn operands_mul() {
792 let k = InstrKind::Mul { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() };
793 assert_eq!(k.operands(), vec![c0(), c1()]);
794 }
795
796 #[test]
797 fn operands_udiv() {
798 let k = InstrKind::UDiv { exact: false, lhs: c0(), rhs: c1() };
799 assert_eq!(k.operands(), vec![c0(), c1()]);
800 }
801
802 #[test]
803 fn operands_sdiv() {
804 let k = InstrKind::SDiv { exact: true, lhs: c0(), rhs: c1() };
805 assert_eq!(k.operands(), vec![c0(), c1()]);
806 }
807
808 #[test]
809 fn operands_urem() {
810 let k = InstrKind::URem { lhs: c0(), rhs: c1() };
811 assert_eq!(k.operands(), vec![c0(), c1()]);
812 }
813
814 #[test]
815 fn operands_srem() {
816 let k = InstrKind::SRem { lhs: c0(), rhs: c1() };
817 assert_eq!(k.operands(), vec![c0(), c1()]);
818 }
819
820 #[test]
823 fn operands_and() {
824 assert_eq!(InstrKind::And { lhs: c0(), rhs: c1() }.operands(), vec![c0(), c1()]);
825 }
826
827 #[test]
828 fn operands_or() {
829 assert_eq!(InstrKind::Or { lhs: c0(), rhs: c1() }.operands(), vec![c0(), c1()]);
830 }
831
832 #[test]
833 fn operands_xor() {
834 assert_eq!(InstrKind::Xor { lhs: c0(), rhs: c1() }.operands(), vec![c0(), c1()]);
835 }
836
837 #[test]
838 fn operands_shl() {
839 let k = InstrKind::Shl { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() };
840 assert_eq!(k.operands(), vec![c0(), c1()]);
841 }
842
843 #[test]
844 fn operands_lshr() {
845 assert_eq!(InstrKind::LShr { exact: false, lhs: c0(), rhs: c1() }.operands(), vec![c0(), c1()]);
846 }
847
848 #[test]
849 fn operands_ashr() {
850 assert_eq!(InstrKind::AShr { exact: false, lhs: c0(), rhs: c1() }.operands(), vec![c0(), c1()]);
851 }
852
853 #[test]
856 fn operands_fadd() {
857 let k = InstrKind::FAdd { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() };
858 assert_eq!(k.operands(), vec![c0(), c1()]);
859 }
860
861 #[test]
862 fn operands_fsub() {
863 let k = InstrKind::FSub { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() };
864 assert_eq!(k.operands(), vec![c0(), c1()]);
865 }
866
867 #[test]
868 fn operands_fmul() {
869 let k = InstrKind::FMul { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() };
870 assert_eq!(k.operands(), vec![c0(), c1()]);
871 }
872
873 #[test]
874 fn operands_fdiv() {
875 let k = InstrKind::FDiv { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() };
876 assert_eq!(k.operands(), vec![c0(), c1()]);
877 }
878
879 #[test]
880 fn operands_frem() {
881 let k = InstrKind::FRem { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() };
882 assert_eq!(k.operands(), vec![c0(), c1()]);
883 }
884
885 #[test]
886 fn operands_fneg() {
887 let k = InstrKind::FNeg { flags: FastMathFlags::default(), operand: c0() };
888 assert_eq!(k.operands(), vec![c0()]);
889 }
890
891 #[test]
894 fn operands_icmp() {
895 let k = InstrKind::ICmp { pred: IntPredicate::Eq, lhs: c0(), rhs: c1() };
896 assert_eq!(k.operands(), vec![c0(), c1()]);
897 }
898
899 #[test]
900 fn operands_fcmp() {
901 let k = InstrKind::FCmp {
902 flags: FastMathFlags::default(),
903 pred: FloatPredicate::Oeq,
904 lhs: c0(),
905 rhs: c1(),
906 };
907 assert_eq!(k.operands(), vec![c0(), c1()]);
908 }
909
910 #[test]
913 fn operands_alloca_no_count() {
914 let ctx = Context::new();
915 let k = InstrKind::Alloca { alloc_ty: ctx.i32_ty, num_elements: None, align: None };
916 assert_eq!(k.operands(), vec![]);
917 }
918
919 #[test]
920 fn operands_alloca_with_count() {
921 let ctx = Context::new();
922 let k = InstrKind::Alloca { alloc_ty: ctx.i32_ty, num_elements: Some(c0()), align: None };
923 assert_eq!(k.operands(), vec![c0()]);
924 }
925
926 #[test]
927 fn operands_load() {
928 let ctx = Context::new();
929 let k = InstrKind::Load { ty: ctx.i32_ty, ptr: c0(), align: None, volatile: false };
930 assert_eq!(k.operands(), vec![c0()]);
931 }
932
933 #[test]
934 fn operands_store() {
935 let k = InstrKind::Store { val: c0(), ptr: c1(), align: None, volatile: false };
936 assert_eq!(k.operands(), vec![c0(), c1()]);
937 }
938
939 #[test]
940 fn operands_gep_no_indices() {
941 let ctx = Context::new();
942 let k = InstrKind::GetElementPtr {
943 inbounds: false,
944 base_ty: ctx.i32_ty,
945 ptr: c0(),
946 indices: vec![],
947 };
948 assert_eq!(k.operands(), vec![c0()]);
949 }
950
951 #[test]
952 fn operands_gep_two_indices() {
953 let ctx = Context::new();
954 let k = InstrKind::GetElementPtr {
955 inbounds: true,
956 base_ty: ctx.i32_ty,
957 ptr: c0(),
958 indices: vec![c1(), v0()],
959 };
960 assert_eq!(k.operands(), vec![c0(), c1(), v0()]);
961 }
962
963 #[test]
966 fn operands_trunc() {
967 let ctx = Context::new();
968 assert_eq!(InstrKind::Trunc { val: c0(), to: ctx.i8_ty }.operands(), vec![c0()]);
969 }
970
971 #[test]
972 fn operands_zext() {
973 let ctx = Context::new();
974 assert_eq!(InstrKind::ZExt { val: c0(), to: ctx.i64_ty }.operands(), vec![c0()]);
975 }
976
977 #[test]
978 fn operands_sext() {
979 let ctx = Context::new();
980 assert_eq!(InstrKind::SExt { val: c0(), to: ctx.i64_ty }.operands(), vec![c0()]);
981 }
982
983 #[test]
984 fn operands_fptrunc() {
985 let ctx = Context::new();
986 let f32_ty = ctx.f32_ty;
987 assert_eq!(InstrKind::FPTrunc { val: c0(), to: f32_ty }.operands(), vec![c0()]);
988 }
989
990 #[test]
991 fn operands_fpext() {
992 let ctx = Context::new();
993 let f64_ty = ctx.f64_ty;
994 assert_eq!(InstrKind::FPExt { val: c0(), to: f64_ty }.operands(), vec![c0()]);
995 }
996
997 #[test]
998 fn operands_fptoui() {
999 let ctx = Context::new();
1000 assert_eq!(InstrKind::FPToUI { val: c0(), to: ctx.i64_ty }.operands(), vec![c0()]);
1001 }
1002
1003 #[test]
1004 fn operands_fptosi() {
1005 let ctx = Context::new();
1006 assert_eq!(InstrKind::FPToSI { val: c0(), to: ctx.i64_ty }.operands(), vec![c0()]);
1007 }
1008
1009 #[test]
1010 fn operands_uitofp() {
1011 let ctx = Context::new();
1012 let f64_ty = ctx.f64_ty;
1013 assert_eq!(InstrKind::UIToFP { val: c0(), to: f64_ty }.operands(), vec![c0()]);
1014 }
1015
1016 #[test]
1017 fn operands_sitofp() {
1018 let ctx = Context::new();
1019 let f64_ty = ctx.f64_ty;
1020 assert_eq!(InstrKind::SIToFP { val: c0(), to: f64_ty }.operands(), vec![c0()]);
1021 }
1022
1023 #[test]
1024 fn operands_ptrtoint() {
1025 let ctx = Context::new();
1026 assert_eq!(InstrKind::PtrToInt { val: c0(), to: ctx.i64_ty }.operands(), vec![c0()]);
1027 }
1028
1029 #[test]
1030 fn operands_inttoptr() {
1031 let ctx = Context::new();
1032 let ptr_ty = ctx.ptr_ty;
1033 assert_eq!(InstrKind::IntToPtr { val: c0(), to: ptr_ty }.operands(), vec![c0()]);
1034 }
1035
1036 #[test]
1037 fn operands_bitcast() {
1038 let ctx = Context::new();
1039 let ptr_ty = ctx.ptr_ty;
1040 assert_eq!(InstrKind::BitCast { val: c0(), to: ptr_ty }.operands(), vec![c0()]);
1041 }
1042
1043 #[test]
1044 fn operands_addrspacecast() {
1045 let ctx = Context::new();
1046 let ptr_ty = ctx.ptr_ty;
1047 assert_eq!(InstrKind::AddrSpaceCast { val: c0(), to: ptr_ty }.operands(), vec![c0()]);
1048 }
1049
1050 #[test]
1053 fn operands_select() {
1054 let k = InstrKind::Select { cond: c0(), then_val: c1(), else_val: v0() };
1055 assert_eq!(k.operands(), vec![c0(), c1(), v0()]);
1056 }
1057
1058 #[test]
1059 fn operands_phi_empty() {
1060 let ctx = Context::new();
1061 let k = InstrKind::Phi { ty: ctx.i32_ty, incoming: vec![] };
1062 assert_eq!(k.operands(), vec![]);
1063 }
1064
1065 #[test]
1066 fn operands_phi_two_incoming() {
1067 let ctx = Context::new();
1068 let k = InstrKind::Phi {
1070 ty: ctx.i32_ty,
1071 incoming: vec![(c0(), b0()), (c1(), b1())],
1072 };
1073 assert_eq!(k.operands(), vec![c0(), c1()]);
1074 }
1075
1076 #[test]
1077 fn operands_extractvalue() {
1078 let k = InstrKind::ExtractValue { aggregate: c0(), indices: vec![0, 1] };
1079 assert_eq!(k.operands(), vec![c0()]);
1080 }
1081
1082 #[test]
1083 fn operands_insertvalue() {
1084 let k = InstrKind::InsertValue { aggregate: c0(), val: c1(), indices: vec![0] };
1085 assert_eq!(k.operands(), vec![c0(), c1()]);
1086 }
1087
1088 #[test]
1089 fn operands_extractelement() {
1090 let k = InstrKind::ExtractElement { vec: c0(), idx: c1() };
1091 assert_eq!(k.operands(), vec![c0(), c1()]);
1092 }
1093
1094 #[test]
1095 fn operands_insertelement() {
1096 let k = InstrKind::InsertElement { vec: c0(), val: c1(), idx: v0() };
1097 assert_eq!(k.operands(), vec![c0(), c1(), v0()]);
1098 }
1099
1100 #[test]
1101 fn operands_shufflevector() {
1102 let k = InstrKind::ShuffleVector { v1: c0(), v2: c1(), mask: vec![0, 1, 0, 1] };
1104 assert_eq!(k.operands(), vec![c0(), c1()]);
1105 }
1106
1107 #[test]
1110 fn operands_call_no_args() {
1111 let mut ctx = Context::new();
1112 let callee_ty = ctx.mk_fn_type(ctx.void_ty, vec![], false);
1113 let k = InstrKind::Call {
1114 tail: TailCallKind::None,
1115 callee_ty,
1116 callee: c0(),
1117 args: vec![],
1118 };
1119 assert_eq!(k.operands(), vec![c0()]);
1121 }
1122
1123 #[test]
1124 fn operands_call_with_args() {
1125 let mut ctx = Context::new();
1126 let callee_ty = ctx.mk_fn_type(ctx.void_ty, vec![ctx.i32_ty, ctx.i32_ty], false);
1127 let k = InstrKind::Call {
1128 tail: TailCallKind::None,
1129 callee_ty,
1130 callee: c0(),
1131 args: vec![c1(), c2()],
1132 };
1133 assert_eq!(k.operands(), vec![c0(), c1(), c2()]);
1134 }
1135
1136 #[test]
1139 fn operands_ret_void() {
1140 assert_eq!(InstrKind::Ret { val: None }.operands(), vec![]);
1141 }
1142
1143 #[test]
1144 fn operands_ret_value() {
1145 assert_eq!(InstrKind::Ret { val: Some(c0()) }.operands(), vec![c0()]);
1146 }
1147
1148 #[test]
1149 fn operands_br() {
1150 assert_eq!(InstrKind::Br { dest: b0() }.operands(), vec![]);
1152 }
1153
1154 #[test]
1155 fn operands_condbr() {
1156 let k = InstrKind::CondBr { cond: c0(), then_dest: b0(), else_dest: b1() };
1157 assert_eq!(k.operands(), vec![c0()]);
1159 }
1160
1161 #[test]
1162 fn operands_switch_two_cases() {
1163 let k = InstrKind::Switch {
1165 val: c0(),
1166 default: b0(),
1167 cases: vec![(c1(), b1()), (c2(), b0())],
1168 };
1169 assert_eq!(k.operands(), vec![c0(), c1(), c2()]);
1170 }
1171
1172 #[test]
1173 fn operands_unreachable() {
1174 assert_eq!(InstrKind::Unreachable.operands(), vec![]);
1175 }
1176
1177 #[test]
1180 fn successors_br() {
1181 assert_eq!(InstrKind::Br { dest: b0() }.successors(), vec![b0()]);
1182 }
1183
1184 #[test]
1185 fn successors_condbr() {
1186 let k = InstrKind::CondBr { cond: c0(), then_dest: b0(), else_dest: b1() };
1187 assert_eq!(k.successors(), vec![b0(), b1()]);
1188 }
1189
1190 #[test]
1191 fn successors_switch_default_plus_cases() {
1192 let k = InstrKind::Switch {
1193 val: c0(),
1194 default: b0(),
1195 cases: vec![(c1(), b1()), (c2(), b0())],
1196 };
1197 assert_eq!(k.successors(), vec![b0(), b1(), b0()]);
1198 }
1199
1200 #[test]
1201 fn successors_switch_no_cases() {
1202 let k = InstrKind::Switch { val: c0(), default: b1(), cases: vec![] };
1203 assert_eq!(k.successors(), vec![b1()]);
1204 }
1205
1206 #[test]
1207 fn successors_ret_void() {
1208 assert_eq!(InstrKind::Ret { val: None }.successors(), vec![]);
1209 }
1210
1211 #[test]
1212 fn successors_ret_value() {
1213 assert_eq!(InstrKind::Ret { val: Some(c0()) }.successors(), vec![]);
1214 }
1215
1216 #[test]
1217 fn successors_unreachable() {
1218 assert_eq!(InstrKind::Unreachable.successors(), vec![]);
1219 }
1220
1221 #[test]
1224 fn successors_non_terminators_are_empty() {
1225 let mut ctx = Context::new();
1226 let callee_ty = ctx.mk_fn_type(ctx.void_ty, vec![], false);
1227 let cases: &[InstrKind] = &[
1229 InstrKind::Add { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() },
1230 InstrKind::Sub { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() },
1231 InstrKind::Mul { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() },
1232 InstrKind::UDiv { exact: false, lhs: c0(), rhs: c1() },
1233 InstrKind::SDiv { exact: false, lhs: c0(), rhs: c1() },
1234 InstrKind::URem { lhs: c0(), rhs: c1() },
1235 InstrKind::SRem { lhs: c0(), rhs: c1() },
1236 InstrKind::And { lhs: c0(), rhs: c1() },
1237 InstrKind::Or { lhs: c0(), rhs: c1() },
1238 InstrKind::Xor { lhs: c0(), rhs: c1() },
1239 InstrKind::Shl { flags: IntArithFlags::default(), lhs: c0(), rhs: c1() },
1240 InstrKind::LShr { exact: false, lhs: c0(), rhs: c1() },
1241 InstrKind::AShr { exact: false, lhs: c0(), rhs: c1() },
1242 InstrKind::FAdd { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() },
1243 InstrKind::FSub { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() },
1244 InstrKind::FMul { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() },
1245 InstrKind::FDiv { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() },
1246 InstrKind::FRem { flags: FastMathFlags::default(), lhs: c0(), rhs: c1() },
1247 InstrKind::FNeg { flags: FastMathFlags::default(), operand: c0() },
1248 InstrKind::ICmp { pred: IntPredicate::Eq, lhs: c0(), rhs: c1() },
1249 InstrKind::FCmp { flags: FastMathFlags::default(), pred: FloatPredicate::Oeq, lhs: c0(), rhs: c1() },
1250 InstrKind::Alloca { alloc_ty: ctx.i32_ty, num_elements: None, align: None },
1251 InstrKind::Load { ty: ctx.i32_ty, ptr: c0(), align: None, volatile: false },
1252 InstrKind::Store { val: c0(), ptr: c1(), align: None, volatile: false },
1253 InstrKind::GetElementPtr { inbounds: false, base_ty: ctx.i32_ty, ptr: c0(), indices: vec![] },
1254 InstrKind::Trunc { val: c0(), to: ctx.i8_ty },
1255 InstrKind::ZExt { val: c0(), to: ctx.i64_ty },
1256 InstrKind::SExt { val: c0(), to: ctx.i64_ty },
1257 InstrKind::FPTrunc { val: c0(), to: ctx.f32_ty },
1258 InstrKind::FPExt { val: c0(), to: ctx.f64_ty },
1259 InstrKind::FPToUI { val: c0(), to: ctx.i64_ty },
1260 InstrKind::FPToSI { val: c0(), to: ctx.i64_ty },
1261 InstrKind::UIToFP { val: c0(), to: ctx.f64_ty },
1262 InstrKind::SIToFP { val: c0(), to: ctx.f64_ty },
1263 InstrKind::PtrToInt { val: c0(), to: ctx.i64_ty },
1264 InstrKind::IntToPtr { val: c0(), to: ctx.ptr_ty },
1265 InstrKind::BitCast { val: c0(), to: ctx.ptr_ty },
1266 InstrKind::AddrSpaceCast { val: c0(), to: ctx.ptr_ty },
1267 InstrKind::Select { cond: c0(), then_val: c1(), else_val: v0() },
1268 InstrKind::Phi { ty: ctx.i32_ty, incoming: vec![] },
1269 InstrKind::ExtractValue { aggregate: c0(), indices: vec![0] },
1270 InstrKind::InsertValue { aggregate: c0(), val: c1(), indices: vec![0] },
1271 InstrKind::ExtractElement { vec: c0(), idx: c1() },
1272 InstrKind::InsertElement { vec: c0(), val: c1(), idx: v0() },
1273 InstrKind::ShuffleVector { v1: c0(), v2: c1(), mask: vec![0, 1] },
1274 InstrKind::Call { tail: TailCallKind::None, callee_ty, callee: c0(), args: vec![] },
1275 ];
1276 for k in cases {
1277 assert_eq!(k.successors(), vec![], "{:?} should have no successors", k);
1278 }
1279 }
1280}