1use crate::debugloc::{DebugLoc, HasDebugLoc};
2use crate::function::{CallingConvention, FunctionAttribute, ParameterAttribute};
3use crate::instruction::{HasResult, InlineAssembly};
4use crate::types::{Typed, Types};
5use crate::{Constant, ConstantRef, Name, Operand, Type, TypeRef};
6use either::Either;
7use std::convert::TryFrom;
8use std::fmt::{self, Display};
9
10#[derive(PartialEq, Clone, Debug, Hash)]
13pub enum Terminator {
14 Ret(Ret),
15 Br(Br),
16 CondBr(CondBr),
17 Switch(Switch),
18 IndirectBr(IndirectBr),
19 Invoke(Invoke),
20 Resume(Resume),
21 Unreachable(Unreachable),
22 CleanupRet(CleanupRet),
23 CatchRet(CatchRet),
24 CatchSwitch(CatchSwitch),
25 CallBr(CallBr),
26}
27
28impl Typed for Terminator {
35 fn get_type(&self, types: &Types) -> TypeRef {
36 match self {
37 Terminator::Ret(t) => types.type_of(t),
38 Terminator::Br(t) => types.type_of(t),
39 Terminator::CondBr(t) => types.type_of(t),
40 Terminator::Switch(t) => types.type_of(t),
41 Terminator::IndirectBr(t) => types.type_of(t),
42 Terminator::Invoke(t) => types.type_of(t),
43 Terminator::Resume(t) => types.type_of(t),
44 Terminator::Unreachable(t) => types.type_of(t),
45 Terminator::CleanupRet(t) => types.type_of(t),
46 Terminator::CatchRet(t) => types.type_of(t),
47 Terminator::CatchSwitch(t) => types.type_of(t),
48 Terminator::CallBr(t) => types.type_of(t),
49 }
50 }
51}
52
53impl HasDebugLoc for Terminator {
54 fn get_debug_loc(&self) -> &Option<DebugLoc> {
55 match self {
56 Terminator::Ret(t) => t.get_debug_loc(),
57 Terminator::Br(t) => t.get_debug_loc(),
58 Terminator::CondBr(t) => t.get_debug_loc(),
59 Terminator::Switch(t) => t.get_debug_loc(),
60 Terminator::IndirectBr(t) => t.get_debug_loc(),
61 Terminator::Invoke(t) => t.get_debug_loc(),
62 Terminator::Resume(t) => t.get_debug_loc(),
63 Terminator::Unreachable(t) => t.get_debug_loc(),
64 Terminator::CleanupRet(t) => t.get_debug_loc(),
65 Terminator::CatchRet(t) => t.get_debug_loc(),
66 Terminator::CatchSwitch(t) => t.get_debug_loc(),
67 Terminator::CallBr(t) => t.get_debug_loc(),
68 }
69 }
70}
71
72impl Display for Terminator {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 match self {
75 Terminator::Ret(t) => write!(f, "{}", t),
76 Terminator::Br(t) => write!(f, "{}", t),
77 Terminator::CondBr(t) => write!(f, "{}", t),
78 Terminator::Switch(t) => write!(f, "{}", t),
79 Terminator::IndirectBr(t) => write!(f, "{}", t),
80 Terminator::Invoke(t) => write!(f, "{}", t),
81 Terminator::Resume(t) => write!(f, "{}", t),
82 Terminator::Unreachable(t) => write!(f, "{}", t),
83 Terminator::CleanupRet(t) => write!(f, "{}", t),
84 Terminator::CatchRet(t) => write!(f, "{}", t),
85 Terminator::CatchSwitch(t) => write!(f, "{}", t),
86 Terminator::CallBr(t) => write!(f, "{}", t),
87 }
88 }
89}
90
91impl Terminator {
113 pub fn try_get_result(&self) -> Option<&Name> {
116 match self {
117 Terminator::Ret(_) => None,
118 Terminator::Br(_) => None,
119 Terminator::CondBr(_) => None,
120 Terminator::Switch(_) => None,
121 Terminator::IndirectBr(_) => None,
122 Terminator::Invoke(t) => Some(&t.result),
123 Terminator::Resume(_) => None,
124 Terminator::Unreachable(_) => None,
125 Terminator::CleanupRet(_) => None,
126 Terminator::CatchRet(_) => None,
127 Terminator::CatchSwitch(t) => Some(&t.result),
128 Terminator::CallBr(t) => Some(&t.result),
129 }
130 }
131}
132
133macro_rules! impl_term {
134 ($term:ty, $id:ident) => {
135 impl From<$term> for Terminator {
136 fn from(term: $term) -> Terminator {
137 Terminator::$id(term)
138 }
139 }
140
141 impl TryFrom<Terminator> for $term {
142 type Error = &'static str;
143 fn try_from(term: Terminator) -> Result<Self, Self::Error> {
144 match term {
145 Terminator::$id(term) => Ok(term),
146 _ => Err("Terminator is not of requested type"),
147 }
148 }
149 }
150
151 impl HasDebugLoc for $term {
152 fn get_debug_loc(&self) -> &Option<DebugLoc> {
153 &self.debugloc
154 }
155 }
156
157 };
165}
166
167macro_rules! impl_hasresult {
168 ($term:ty) => {
169 impl HasResult for $term {
170 fn get_result(&self) -> &Name {
171 &self.result
172 }
173 }
174 };
175}
176
177macro_rules! void_typed {
178 ($term:ty) => {
179 impl Typed for $term {
180 fn get_type(&self, types: &Types) -> TypeRef {
181 types.void()
182 }
183 }
184 };
185}
186
187#[derive(PartialEq, Clone, Debug, Hash)]
189pub struct Ret {
190 pub return_operand: Option<Operand>,
192 pub debugloc: Option<DebugLoc>,
193 }
195
196impl_term!(Ret, Ret);
197void_typed!(Ret); impl Display for Ret {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 write!(
202 f,
203 "ret {}",
204 match &self.return_operand {
205 None => "void".into(),
206 Some(op) => format!("{}", op),
207 },
208 )?;
209 if self.debugloc.is_some() {
210 write!(f, " (with debugloc)")?;
211 }
212 Ok(())
213 }
214}
215
216#[derive(PartialEq, Clone, Debug, Hash)]
220pub struct Br {
221 pub dest: Name,
223 pub debugloc: Option<DebugLoc>,
224 }
226
227impl_term!(Br, Br);
228void_typed!(Br);
229
230impl Display for Br {
231 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232 write!(f, "br label {}", &self.dest)?;
233 if self.debugloc.is_some() {
234 write!(f, " (with debugloc)")?;
235 }
236 Ok(())
237 }
238}
239
240#[derive(PartialEq, Clone, Debug, Hash)]
244pub struct CondBr {
245 pub condition: Operand,
247 pub true_dest: Name,
249 pub false_dest: Name,
251 pub debugloc: Option<DebugLoc>,
252 }
254
255impl_term!(CondBr, CondBr);
256void_typed!(CondBr);
257
258impl Display for CondBr {
259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 write!(
261 f,
262 "br {}, label {}, label {}",
263 &self.condition, &self.true_dest, &self.false_dest,
264 )?;
265 if self.debugloc.is_some() {
266 write!(f, " (with debugloc)")?;
267 }
268 Ok(())
269 }
270}
271
272#[derive(PartialEq, Clone, Debug, Hash)]
274pub struct Switch {
275 pub operand: Operand,
276 pub dests: Vec<(ConstantRef, Name)>,
277 pub default_dest: Name,
278 pub debugloc: Option<DebugLoc>,
279 }
281
282impl_term!(Switch, Switch);
283void_typed!(Switch);
284
285impl Display for Switch {
286 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287 write!(
288 f,
289 "switch {}, label {} [ ",
290 &self.operand, &self.default_dest,
291 )?;
292 for (val, label) in &self.dests {
293 write!(f, "{}, label {}; ", val, label)?;
294 }
295 write!(f, "]")?;
296 if self.debugloc.is_some() {
297 write!(f, " (with debugloc)")?;
298 }
299 Ok(())
300 }
301}
302
303#[derive(PartialEq, Clone, Debug, Hash)]
305pub struct IndirectBr {
306 pub operand: Operand,
308 pub possible_dests: Vec<Name>,
313 pub debugloc: Option<DebugLoc>,
314 }
316
317impl_term!(IndirectBr, IndirectBr);
318void_typed!(IndirectBr);
319
320impl Display for IndirectBr {
321 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322 write!(
323 f,
324 "indirectbr {}, [ label {}",
325 &self.operand,
326 &self
327 .possible_dests
328 .get(0)
329 .expect("IndirectBr with no possible dests"),
330 )?;
331 for dest in &self.possible_dests[1 ..] {
332 write!(f, ", label {}", dest)?;
333 }
334 write!(f, " ]")?;
335 if self.debugloc.is_some() {
336 write!(f, " (with debugloc)")?;
337 }
338 Ok(())
339 }
340}
341
342#[derive(PartialEq, Clone, Debug, Hash)]
344pub struct Invoke {
345 pub function: Either<InlineAssembly, Operand>,
346 #[cfg(feature = "llvm-15-or-greater")]
347 pub function_ty: TypeRef,
348 pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
349 pub return_attributes: Vec<ParameterAttribute>,
350 pub result: Name, pub return_label: Name, pub exception_label: Name, pub function_attributes: Vec<FunctionAttribute>, pub calling_convention: CallingConvention,
355 pub debugloc: Option<DebugLoc>,
356 }
358
359impl_term!(Invoke, Invoke);
360impl_hasresult!(Invoke);
361
362#[cfg(feature = "llvm-14-or-lower")]
363impl Typed for Invoke {
364 fn get_type(&self, types: &Types) -> TypeRef {
365 match types.type_of(&self.function).as_ref() {
366 Type::PointerType { pointee_type, .. } => match pointee_type.as_ref() {
367 Type::FuncType { result_type, .. } => result_type.clone(),
368 ty => panic!("Expected Invoke's function argument to be of type pointer-to-function, got pointer-to-{:?}", ty),
369 },
370 ty => panic!("Expected Invoke's function argument to be of type pointer-to-function, got {:?}", ty),
371 }
372 }
373}
374#[cfg(feature = "llvm-15-or-greater")]
375impl Typed for Invoke {
376 fn get_type(&self, _types: &Types) -> TypeRef {
377 match self.function_ty.as_ref() {
378 Type::FuncType { result_type, .. } => result_type.clone(),
379 ty => panic!("Expected Invoke.function_ty to be a FuncType, got {:?}", ty),
380 }
381 }
382}
383
384impl Display for Invoke {
385 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
386 write!(
389 f,
390 "{} = invoke {}(",
391 &self.result,
392 match &self.function {
393 Either::Left(_) => "<inline assembly>".into(),
394 Either::Right(op) => format!("{}", op),
395 }
396 )?;
397 for (i, (arg, _)) in self.arguments.iter().enumerate() {
398 if i == self.arguments.len() - 1 {
399 write!(f, "{}", arg)?;
400 } else {
401 write!(f, "{}, ", arg)?;
402 }
403 }
404 write!(
405 f,
406 ") to label {} unwind label {}",
407 &self.return_label, &self.exception_label,
408 )?;
409 if self.debugloc.is_some() {
410 write!(f, " (with debugloc)")?;
411 }
412 Ok(())
413 }
414}
415
416#[derive(PartialEq, Clone, Debug, Hash)]
418pub struct Resume {
419 pub operand: Operand,
420 pub debugloc: Option<DebugLoc>,
421 }
423
424impl_term!(Resume, Resume);
425void_typed!(Resume);
426
427impl Display for Resume {
428 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
429 write!(f, "resume {}", &self.operand)?;
430 if self.debugloc.is_some() {
431 write!(f, " (with debugloc)")?;
432 }
433 Ok(())
434 }
435}
436
437#[derive(PartialEq, Clone, Debug, Hash)]
439pub struct Unreachable {
440 pub debugloc: Option<DebugLoc>,
441 }
443
444impl_term!(Unreachable, Unreachable);
445void_typed!(Unreachable);
446
447impl Display for Unreachable {
448 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449 write!(f, "unreachable")?;
450 if self.debugloc.is_some() {
451 write!(f, " (with debugloc)")?;
452 }
453 Ok(())
454 }
455}
456
457#[derive(PartialEq, Clone, Debug, Hash)]
459pub struct CleanupRet {
460 pub cleanup_pad: Operand,
461 pub unwind_dest: Option<Name>,
463 pub debugloc: Option<DebugLoc>,
464 }
466
467impl_term!(CleanupRet, CleanupRet);
468void_typed!(CleanupRet);
469
470impl Display for CleanupRet {
471 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
472 write!(
473 f,
474 "cleanupret from {} unwind {}",
475 &self.cleanup_pad,
476 match &self.unwind_dest {
477 None => "to caller".into(),
478 Some(dest) => format!("label {}", dest),
479 },
480 )?;
481 if self.debugloc.is_some() {
482 write!(f, " (with debugloc)")?;
483 }
484 Ok(())
485 }
486}
487
488#[derive(PartialEq, Clone, Debug, Hash)]
490pub struct CatchRet {
491 pub catch_pad: Operand,
492 pub successor: Name,
493 pub debugloc: Option<DebugLoc>,
494 }
496
497impl_term!(CatchRet, CatchRet);
498void_typed!(CatchRet);
499
500impl Display for CatchRet {
501 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
502 write!(
503 f,
504 "catchret from {} to label {}",
505 &self.catch_pad, &self.successor,
506 )?;
507 if self.debugloc.is_some() {
508 write!(f, " (with debugloc)")?;
509 }
510 Ok(())
511 }
512}
513
514#[derive(PartialEq, Clone, Debug, Hash)]
516pub struct CatchSwitch {
517 pub parent_pad: Operand,
518 pub catch_handlers: Vec<Name>,
520 pub default_unwind_dest: Option<Name>,
522 pub result: Name,
523 pub debugloc: Option<DebugLoc>,
524 }
526
527impl_term!(CatchSwitch, CatchSwitch);
528impl_hasresult!(CatchSwitch);
529
530impl Typed for CatchSwitch {
531 fn get_type(&self, _types: &Types) -> TypeRef {
532 unimplemented!("Typed for CatchSwitch")
533 }
535}
536
537impl Display for CatchSwitch {
538 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
539 write!(
540 f,
541 "{} = catchswitch within {} [ label {}",
542 &self.result,
543 &self.parent_pad,
544 &self
545 .catch_handlers
546 .get(0)
547 .expect("CatchSwitch with no handlers"),
548 )?;
549 for handler in &self.catch_handlers[1 ..] {
550 write!(f, ", label {}", handler)?;
551 }
552 write!(
553 f,
554 " ] unwind {}",
555 match &self.default_unwind_dest {
556 None => "to caller".into(),
557 Some(dest) => format!("label {}", dest),
558 },
559 )?;
560 if self.debugloc.is_some() {
561 write!(f, " (with debugloc)")?;
562 }
563 Ok(())
564 }
565}
566
567#[derive(PartialEq, Clone, Debug, Hash)]
569pub struct CallBr {
570 pub function: Either<InlineAssembly, Operand>,
571 pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
572 pub return_attributes: Vec<ParameterAttribute>,
573 pub result: Name, pub return_label: Name, pub other_labels: (), pub function_attributes: Vec<FunctionAttribute>,
578 pub calling_convention: CallingConvention,
579 pub debugloc: Option<DebugLoc>,
580 }
582
583impl_term!(CallBr, CallBr);
584impl_hasresult!(CallBr);
585
586impl Typed for CallBr {
587 fn get_type(&self, types: &Types) -> TypeRef {
588 match types.type_of(&self.function).as_ref() {
589 Type::FuncType { result_type, .. } => result_type.clone(),
590 ty => panic!(
591 "Expected the function argument of a CallBr to have type FuncType; got {:?}",
592 ty
593 ),
594 }
595 }
596}
597
598impl Display for CallBr {
599 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600 write!(
604 f,
605 "{} = callbr {}(",
606 &self.result,
607 match &self.function {
608 Either::Left(_) => "<inline assembly>".into(),
609 Either::Right(op) => format!("{}", op),
610 }
611 )?;
612 for (i, (arg, _)) in self.arguments.iter().enumerate() {
613 if i == self.arguments.len() - 1 {
614 write!(f, "{}", arg)?;
615 } else {
616 write!(f, "{}, ", arg)?;
617 }
618 }
619 write!(f, ") to label {}", &self.return_label)?;
620 if self.debugloc.is_some() {
621 write!(f, " (with debugloc)")?;
622 }
623 Ok(())
624 }
625}
626
627use crate::from_llvm::*;
632use crate::function::FunctionContext;
633use crate::llvm_sys::*;
634use crate::module::ModuleContext;
635use llvm_sys::LLVMOpcode;
636
637impl Terminator {
638 #[rustfmt::skip] pub(crate) fn from_llvm_ref(
640 term: LLVMValueRef,
641 ctx: &mut ModuleContext,
642 func_ctx: &mut FunctionContext,
643 ) -> Self {
644 debug!("Processing terminator {:?}", unsafe {
645 print_to_string(term)
646 });
647 match unsafe { LLVMGetInstructionOpcode(term) } {
648 LLVMOpcode::LLVMRet => {
649 Terminator::Ret(Ret::from_llvm_ref(term, ctx, func_ctx))
650 },
651 LLVMOpcode::LLVMBr => match unsafe { LLVMGetNumOperands(term) } {
652 1 => Terminator::Br(Br::from_llvm_ref(term, func_ctx)),
653 3 => Terminator::CondBr(CondBr::from_llvm_ref(term, ctx, func_ctx)),
654 n => panic!("LLVMBr with {} operands, expected 1 or 3", n),
655 },
656 LLVMOpcode::LLVMSwitch => {
657 Terminator::Switch(Switch::from_llvm_ref(term, ctx, func_ctx))
658 },
659 LLVMOpcode::LLVMIndirectBr => {
660 Terminator::IndirectBr(IndirectBr::from_llvm_ref(term, ctx, func_ctx))
661 },
662 LLVMOpcode::LLVMInvoke => {
663 Terminator::Invoke(Invoke::from_llvm_ref(term, ctx, func_ctx))
664 },
665 LLVMOpcode::LLVMResume => {
666 Terminator::Resume(Resume::from_llvm_ref(term, ctx, func_ctx))
667 },
668 LLVMOpcode::LLVMUnreachable => {
669 Terminator::Unreachable(Unreachable::from_llvm_ref(term))
670 },
671 LLVMOpcode::LLVMCleanupRet => {
672 Terminator::CleanupRet(CleanupRet::from_llvm_ref(term, ctx, func_ctx))
673 },
674 LLVMOpcode::LLVMCatchRet => {
675 Terminator::CatchRet(CatchRet::from_llvm_ref(term, ctx, func_ctx))
676 },
677 LLVMOpcode::LLVMCatchSwitch => {
678 Terminator::CatchSwitch(CatchSwitch::from_llvm_ref(term, ctx, func_ctx))
679 },
680 LLVMOpcode::LLVMCallBr => {
681 Terminator::CallBr(CallBr::from_llvm_ref(term, ctx, func_ctx))
682 },
683 opcode => panic!(
684 "Terminator::from_llvm_ref called with a non-terminator instruction (opcode {:?})",
685 opcode
686 ),
687 }
688 }
689}
690
691impl Ret {
692 pub(crate) fn from_llvm_ref(
693 term: LLVMValueRef,
694 ctx: &mut ModuleContext,
695 func_ctx: &mut FunctionContext,
696 ) -> Self {
697 Self {
698 return_operand: match unsafe { LLVMGetNumOperands(term) } {
699 0 => None,
700 1 => Some(Operand::from_llvm_ref(
701 unsafe { LLVMGetOperand(term, 0) },
702 ctx,
703 func_ctx,
704 )),
705 n => panic!("Ret instruction with {} operands", n),
706 },
707 debugloc: DebugLoc::from_llvm_with_col(term),
708 }
710 }
711}
712
713impl Br {
714 pub(crate) fn from_llvm_ref(term: LLVMValueRef, func_ctx: &mut FunctionContext) -> Self {
715 assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
716 Self {
717 dest: func_ctx
718 .bb_names
719 .get(unsafe { &op_to_bb(LLVMGetOperand(term, 0)) })
720 .expect("Failed to find destination bb in map")
721 .clone(),
722 debugloc: DebugLoc::from_llvm_with_col(term),
723 }
725 }
726}
727
728impl CondBr {
729 pub(crate) fn from_llvm_ref(
730 term: LLVMValueRef,
731 ctx: &mut ModuleContext,
732 func_ctx: &mut FunctionContext,
733 ) -> Self {
734 assert_eq!(unsafe { LLVMGetNumOperands(term) }, 3);
735 Self {
736 condition: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
737 true_dest: func_ctx
738 .bb_names
739 .get(unsafe { &op_to_bb(LLVMGetOperand(term, 2)) })
740 .expect("Failed to find true-destination bb in map")
741 .clone(),
742 false_dest: func_ctx
743 .bb_names
744 .get(unsafe { &op_to_bb(LLVMGetOperand(term, 1)) })
745 .expect("Failed to find false-destination in bb map")
746 .clone(),
747 debugloc: DebugLoc::from_llvm_with_col(term),
748 }
750 }
751}
752
753impl Switch {
754 pub(crate) fn from_llvm_ref(
755 term: LLVMValueRef,
756 ctx: &mut ModuleContext,
757 func_ctx: &mut FunctionContext,
758 ) -> Self {
759 Self {
760 operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
761 dests: {
762 let num_dests = unsafe { LLVMGetNumSuccessors(term) };
763 let dest_bbs = (1 ..= num_dests) .map(|i| {
765 func_ctx
766 .bb_names
767 .get(unsafe { &LLVMGetSuccessor(term, i) })
768 .expect("Failed to find switch destination in map")
769 .clone()
770 });
771 let dest_vals = (1 .. num_dests).map(|i| {
772 Constant::from_llvm_ref(unsafe { LLVMGetOperand(term, 2 * i) }, ctx)
773 });
775 Iterator::zip(dest_vals, dest_bbs).collect()
776 },
777 default_dest: func_ctx
778 .bb_names
779 .get(unsafe { &LLVMGetSwitchDefaultDest(term) })
780 .expect("Failed to find switch default destination in map")
781 .clone(),
782 debugloc: DebugLoc::from_llvm_with_col(term),
783 }
785 }
786}
787
788impl IndirectBr {
789 pub(crate) fn from_llvm_ref(
790 term: LLVMValueRef,
791 ctx: &mut ModuleContext,
792 func_ctx: &mut FunctionContext,
793 ) -> Self {
794 Self {
795 operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
796 possible_dests: {
797 let num_dests = unsafe { LLVMGetNumSuccessors(term) };
798 (0 .. num_dests)
799 .map(|i| {
800 func_ctx
801 .bb_names
802 .get(unsafe { &LLVMGetSuccessor(term, i) })
803 .expect("Failed to find indirect branch destination in map")
804 .clone()
805 })
806 .collect()
807 },
808 debugloc: DebugLoc::from_llvm_with_col(term),
809 }
811 }
812}
813
814impl Invoke {
815 pub(crate) fn from_llvm_ref(
816 term: LLVMValueRef,
817 ctx: &mut ModuleContext,
818 func_ctx: &mut FunctionContext,
819 ) -> Self {
820 use crate::instruction::CallInfo;
821 let callinfo = CallInfo::from_llvm_ref(term, ctx, func_ctx);
822 Self {
823 function: callinfo.function,
824 #[cfg(feature = "llvm-15-or-greater")]
825 function_ty: callinfo.function_ty,
826 arguments: callinfo.arguments,
827 return_attributes: callinfo.return_attributes,
828 result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
829 return_label: func_ctx
830 .bb_names
831 .get(unsafe { &LLVMGetNormalDest(term) })
832 .expect("Failed to find invoke return destination in map")
833 .clone(),
834 exception_label: func_ctx
835 .bb_names
836 .get(unsafe { &LLVMGetUnwindDest(term) })
837 .expect("Failed to find invoke exception destination in map")
838 .clone(),
839 function_attributes: callinfo.function_attributes,
840 calling_convention: callinfo.calling_convention,
841 debugloc: DebugLoc::from_llvm_with_col(term),
842 }
844 }
845}
846
847impl Resume {
848 pub(crate) fn from_llvm_ref(
849 term: LLVMValueRef,
850 ctx: &mut ModuleContext,
851 func_ctx: &mut FunctionContext,
852 ) -> Self {
853 assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
854 Self {
855 operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
856 debugloc: DebugLoc::from_llvm_with_col(term),
857 }
859 }
860}
861
862impl Unreachable {
863 pub(crate) fn from_llvm_ref(term: LLVMValueRef) -> Self {
864 assert_eq!(unsafe { LLVMGetNumOperands(term) }, 0);
865 Self {
866 debugloc: DebugLoc::from_llvm_with_col(term),
867 }
869 }
870}
871
872impl CleanupRet {
873 pub(crate) fn from_llvm_ref(
874 term: LLVMValueRef,
875 ctx: &mut ModuleContext,
876 func_ctx: &mut FunctionContext,
877 ) -> Self {
878 assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
879 Self {
880 cleanup_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
881 unwind_dest: {
882 let dest = unsafe { LLVMGetUnwindDest(term) };
883 if dest.is_null() {
884 None
885 } else {
886 Some(
887 func_ctx
888 .bb_names
889 .get(&dest)
890 .unwrap_or_else(|| {
891 let names: Vec<_> = func_ctx.bb_names.values().collect();
892 panic!(
893 "Failed to find unwind destination in map; have names {:?}",
894 names
895 )
896 })
897 .clone(),
898 )
899 }
900 },
901 debugloc: DebugLoc::from_llvm_with_col(term),
902 }
904 }
905}
906
907impl CatchRet {
908 pub(crate) fn from_llvm_ref(
909 term: LLVMValueRef,
910 ctx: &mut ModuleContext,
911 func_ctx: &mut FunctionContext,
912 ) -> Self {
913 Self {
914 catch_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
915 successor: func_ctx
916 .bb_names
917 .get(unsafe { &LLVMGetSuccessor(term, 0) })
918 .expect("Failed to find CatchRet successor in map")
919 .clone(),
920 debugloc: DebugLoc::from_llvm_with_col(term),
921 }
923 }
924}
925
926impl CatchSwitch {
927 pub(crate) fn from_llvm_ref(
928 term: LLVMValueRef,
929 ctx: &mut ModuleContext,
930 func_ctx: &mut FunctionContext,
931 ) -> Self {
932 Self {
933 parent_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
934 catch_handlers: {
935 let num_handlers = unsafe { LLVMGetNumHandlers(term) };
936 let mut handlers: Vec<LLVMBasicBlockRef> =
937 Vec::with_capacity(num_handlers as usize);
938 unsafe {
939 LLVMGetHandlers(term, handlers.as_mut_ptr());
940 handlers.set_len(num_handlers as usize);
941 };
942 handlers
943 .into_iter()
944 .map(|h| {
945 func_ctx
946 .bb_names
947 .get(&h)
948 .expect("Failed to find catch handler in map")
949 .clone()
950 })
951 .collect()
952 },
953 default_unwind_dest: {
954 let dest = unsafe { LLVMGetUnwindDest(term) };
955 if dest.is_null() {
956 None
957 } else {
958 Some(func_ctx.bb_names.get(&dest)
959 .unwrap_or_else(|| { let names: Vec<_> = func_ctx.bb_names.values().collect(); panic!("Failed to find CatchSwitch default unwind destination in map; have names {:?}", names) })
960 .clone()
961 )
962 }
963 },
964 result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
965 debugloc: DebugLoc::from_llvm_with_col(term),
966 }
968 }
969}
970
971impl CallBr {
972 pub(crate) fn from_llvm_ref(
973 term: LLVMValueRef,
974 ctx: &mut ModuleContext,
975 func_ctx: &mut FunctionContext,
976 ) -> Self {
977 use crate::instruction::CallInfo;
978 let callinfo = CallInfo::from_llvm_ref(term, ctx, func_ctx);
979 Self {
980 function: callinfo.function,
981 arguments: callinfo.arguments,
982 return_attributes: callinfo.return_attributes,
983 result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
984 return_label: func_ctx
985 .bb_names
986 .get(unsafe { &LLVMGetNormalDest(term) })
987 .expect("Failed to find invoke return destination in map")
988 .clone(),
989 other_labels: (),
990 function_attributes: callinfo.function_attributes,
991 calling_convention: callinfo.calling_convention,
992 debugloc: DebugLoc::from_llvm_with_col(term),
993 }
995 }
996}