#[cfg(feature="llvm-9-or-greater")]
use crate::debugloc::{DebugLoc, HasDebugLoc};
use crate::function::{CallingConvention, FunctionAttribute, ParameterAttribute};
use crate::instruction::{HasResult, InlineAssembly};
use crate::types::{Typed, Types};
use crate::{Constant, ConstantRef, Name, Operand, Type, TypeRef};
use either::Either;
use std::convert::TryFrom;
use std::fmt::{self, Display};
#[derive(PartialEq, Clone, Debug)]
pub enum Terminator {
Ret(Ret),
Br(Br),
CondBr(CondBr),
Switch(Switch),
IndirectBr(IndirectBr),
Invoke(Invoke),
Resume(Resume),
Unreachable(Unreachable),
CleanupRet(CleanupRet),
CatchRet(CatchRet),
CatchSwitch(CatchSwitch),
#[cfg(feature="llvm-9-or-greater")]
CallBr(CallBr),
}
impl Typed for Terminator {
fn get_type(&self, types: &Types) -> TypeRef {
match self {
Terminator::Ret(t) => types.type_of(t),
Terminator::Br(t) => types.type_of(t),
Terminator::CondBr(t) => types.type_of(t),
Terminator::Switch(t) => types.type_of(t),
Terminator::IndirectBr(t) => types.type_of(t),
Terminator::Invoke(t) => types.type_of(t),
Terminator::Resume(t) => types.type_of(t),
Terminator::Unreachable(t) => types.type_of(t),
Terminator::CleanupRet(t) => types.type_of(t),
Terminator::CatchRet(t) => types.type_of(t),
Terminator::CatchSwitch(t) => types.type_of(t),
#[cfg(feature="llvm-9-or-greater")]
Terminator::CallBr(t) => types.type_of(t),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl HasDebugLoc for Terminator {
fn get_debug_loc(&self) -> &Option<DebugLoc> {
match self {
Terminator::Ret(t) => t.get_debug_loc(),
Terminator::Br(t) => t.get_debug_loc(),
Terminator::CondBr(t) => t.get_debug_loc(),
Terminator::Switch(t) => t.get_debug_loc(),
Terminator::IndirectBr(t) => t.get_debug_loc(),
Terminator::Invoke(t) => t.get_debug_loc(),
Terminator::Resume(t) => t.get_debug_loc(),
Terminator::Unreachable(t) => t.get_debug_loc(),
Terminator::CleanupRet(t) => t.get_debug_loc(),
Terminator::CatchRet(t) => t.get_debug_loc(),
Terminator::CatchSwitch(t) => t.get_debug_loc(),
#[cfg(feature="llvm-9-or-greater")]
Terminator::CallBr(t) => t.get_debug_loc(),
}
}
}
impl Display for Terminator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Terminator::Ret(t) => write!(f, "{}", t),
Terminator::Br(t) => write!(f, "{}", t),
Terminator::CondBr(t) => write!(f, "{}", t),
Terminator::Switch(t) => write!(f, "{}", t),
Terminator::IndirectBr(t) => write!(f, "{}", t),
Terminator::Invoke(t) => write!(f, "{}", t),
Terminator::Resume(t) => write!(f, "{}", t),
Terminator::Unreachable(t) => write!(f, "{}", t),
Terminator::CleanupRet(t) => write!(f, "{}", t),
Terminator::CatchRet(t) => write!(f, "{}", t),
Terminator::CatchSwitch(t) => write!(f, "{}", t),
#[cfg(feature="llvm-9-or-greater")]
Terminator::CallBr(t) => write!(f, "{}", t),
}
}
}
macro_rules! impl_term {
($term:ty, $id:ident) => {
impl From<$term> for Terminator {
fn from(term: $term) -> Terminator {
Terminator::$id(term)
}
}
impl TryFrom<Terminator> for $term {
type Error = &'static str;
fn try_from(term: Terminator) -> Result<Self, Self::Error> {
match term {
Terminator::$id(term) => Ok(term),
_ => Err("Terminator is not of requested type"),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl HasDebugLoc for $term {
fn get_debug_loc(&self) -> &Option<DebugLoc> {
&self.debugloc
}
}
};
}
macro_rules! impl_hasresult {
($term:ty) => {
impl HasResult for $term {
fn get_result(&self) -> &Name {
&self.result
}
}
};
}
macro_rules! void_typed {
($term:ty) => {
impl Typed for $term {
fn get_type(&self, types: &Types) -> TypeRef {
types.void()
}
}
};
}
#[derive(PartialEq, Clone, Debug)]
pub struct Ret {
pub return_operand: Option<Operand>,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Ret, Ret);
void_typed!(Ret);
impl Display for Ret {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ret {}",
match &self.return_operand {
None => "void".into(),
Some(op) => format!("{}", op),
},
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Br {
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Br, Br);
void_typed!(Br);
impl Display for Br {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "br label {}", &self.dest)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CondBr {
pub condition: Operand,
pub true_dest: Name,
pub false_dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(CondBr, CondBr);
void_typed!(CondBr);
impl Display for CondBr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "br {}, label {}, label {}",
&self.condition,
&self.true_dest,
&self.false_dest,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Switch {
pub operand: Operand,
pub dests: Vec<(ConstantRef, Name)>,
pub default_dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Switch, Switch);
void_typed!(Switch);
impl Display for Switch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "switch {}, label {} [ ",
&self.operand,
&self.default_dest,
)?;
for (val, label) in &self.dests {
write!(f, "{}, label {}; ", val, label)?;
}
write!(f, "]")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct IndirectBr {
pub operand: Operand,
pub possible_dests: Vec<Name>,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(IndirectBr, IndirectBr);
void_typed!(IndirectBr);
impl Display for IndirectBr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "indirectbr {}, [ label {}",
&self.operand,
&self.possible_dests.get(0).expect("IndirectBr with no possible dests"),
)?;
for dest in &self.possible_dests[1 ..] {
write!(f, ", label {}", dest)?;
}
write!(f, " ]")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Invoke {
pub function: Either<InlineAssembly, Operand>,
pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
pub return_attributes: Vec<ParameterAttribute>,
pub result: Name,
pub return_label: Name,
pub exception_label: Name,
pub function_attributes: Vec<FunctionAttribute>,
pub calling_convention: CallingConvention,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Invoke, Invoke);
impl_hasresult!(Invoke);
impl Typed for Invoke {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.function).as_ref() {
Type::FuncType { result_type, .. } => result_type.clone(),
ty => panic!(
"Expected the function argument of an Invoke to have type FuncType; got {:?}",
ty
),
}
}
}
impl Display for Invoke {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = invoke {}(",
&self.result,
match &self.function {
Either::Left(_) => "<inline assembly>".into(),
Either::Right(op) => format!("{}", op),
}
)?;
for (i, (arg, _)) in self.arguments.iter().enumerate() {
if i == self.arguments.len() - 1 {
write!(f, "{}", arg)?;
} else {
write!(f, "{}, ", arg)?;
}
}
write!(f, ") to label {} unwind label {}",
&self.return_label,
&self.exception_label,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Resume {
pub operand: Operand,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Resume, Resume);
void_typed!(Resume);
impl Display for Resume {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "resume {}", &self.operand)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Unreachable {
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(Unreachable, Unreachable);
void_typed!(Unreachable);
impl Display for Unreachable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "unreachable")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CleanupRet {
pub cleanup_pad: Operand,
pub unwind_dest: Option<Name>,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(CleanupRet, CleanupRet);
void_typed!(CleanupRet);
impl Display for CleanupRet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "cleanupret from {} unwind {}",
&self.cleanup_pad,
match &self.unwind_dest {
None => "to caller".into(),
Some(dest) => format!("label {}", dest),
},
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CatchRet {
pub catch_pad: Operand,
pub successor: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(CatchRet, CatchRet);
void_typed!(CatchRet);
impl Display for CatchRet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "catchret from {} to label {}",
&self.catch_pad,
&self.successor,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CatchSwitch {
pub parent_pad: Operand,
pub catch_handlers: Vec<Name>,
pub default_unwind_dest: Option<Name>,
pub result: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_term!(CatchSwitch, CatchSwitch);
impl_hasresult!(CatchSwitch);
impl Typed for CatchSwitch {
fn get_type(&self, _types: &Types) -> TypeRef {
unimplemented!("Typed for CatchSwitch")
}
}
impl Display for CatchSwitch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = catchswitch within {} [ label {}",
&self.result,
&self.parent_pad,
&self.catch_handlers.get(0).expect("CatchSwitch with no handlers"),
)?;
for handler in &self.catch_handlers[1 ..] {
write!(f, ", label {}", handler)?;
}
write!(f, " ] unwind {}",
match &self.default_unwind_dest {
None => "to caller".into(),
Some(dest) => format!("label {}", dest),
},
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[cfg(feature="llvm-9-or-greater")]
#[derive(PartialEq, Clone, Debug)]
pub struct CallBr {
pub function: Either<InlineAssembly, Operand>,
pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
pub return_attributes: Vec<ParameterAttribute>,
pub result: Name,
pub return_label: Name,
pub other_labels: (),
pub function_attributes: Vec<FunctionAttribute>,
pub calling_convention: CallingConvention,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
#[cfg(feature="llvm-9-or-greater")]
impl_term!(CallBr, CallBr);
#[cfg(feature="llvm-9-or-greater")]
impl_hasresult!(CallBr);
#[cfg(feature="llvm-9-or-greater")]
impl Typed for CallBr {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.function).as_ref() {
Type::FuncType { result_type, .. } => result_type.clone(),
ty => panic!(
"Expected the function argument of a CallBr to have type FuncType; got {:?}",
ty
),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl Display for CallBr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = callbr {}(",
&self.result,
match &self.function {
Either::Left(_) => "<inline assembly>".into(),
Either::Right(op) => format!("{}", op),
}
)?;
for (i, (arg, _)) in self.arguments.iter().enumerate() {
if i == self.arguments.len() - 1 {
write!(f, "{}", arg)?;
} else {
write!(f, "{}, ", arg)?;
}
}
write!(f, ") to label {}", &self.return_label)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
use crate::from_llvm::*;
use crate::function::FunctionContext;
use crate::llvm_sys::*;
use crate::module::ModuleContext;
use llvm_sys::LLVMOpcode;
impl Terminator {
#[rustfmt::skip]
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
debug!("Processing terminator {:?}", unsafe {
print_to_string(term)
});
match unsafe { LLVMGetInstructionOpcode(term) } {
LLVMOpcode::LLVMRet => {
Terminator::Ret(Ret::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMBr => match unsafe { LLVMGetNumOperands(term) } {
1 => Terminator::Br(Br::from_llvm_ref(term, func_ctx)),
3 => Terminator::CondBr(CondBr::from_llvm_ref(term, ctx, func_ctx)),
n => panic!("LLVMBr with {} operands, expected 1 or 3", n),
},
LLVMOpcode::LLVMSwitch => {
Terminator::Switch(Switch::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMIndirectBr => {
Terminator::IndirectBr(IndirectBr::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMInvoke => {
Terminator::Invoke(Invoke::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMResume => {
Terminator::Resume(Resume::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMUnreachable => {
Terminator::Unreachable(Unreachable::from_llvm_ref(term))
},
LLVMOpcode::LLVMCleanupRet => {
Terminator::CleanupRet(CleanupRet::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMCatchRet => {
Terminator::CatchRet(CatchRet::from_llvm_ref(term, ctx, func_ctx))
},
LLVMOpcode::LLVMCatchSwitch => {
Terminator::CatchSwitch(CatchSwitch::from_llvm_ref(term, ctx, func_ctx))
},
#[cfg(feature="llvm-9-or-greater")]
LLVMOpcode::LLVMCallBr => {
Terminator::CallBr(CallBr::from_llvm_ref(term, ctx, func_ctx))
},
opcode => panic!(
"Terminator::from_llvm_ref called with a non-terminator instruction (opcode {:?})",
opcode
),
}
}
}
impl Ret {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
return_operand: match unsafe { LLVMGetNumOperands(term) } {
0 => None,
1 => Some(Operand::from_llvm_ref(
unsafe { LLVMGetOperand(term, 0) },
ctx,
func_ctx,
)),
n => panic!("Ret instruction with {} operands", n),
},
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl Br {
pub(crate) fn from_llvm_ref(term: LLVMValueRef, func_ctx: &mut FunctionContext) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
Self {
dest: func_ctx
.bb_names
.get(unsafe { &op_to_bb(LLVMGetOperand(term, 0)) })
.expect("Failed to find destination bb in map")
.clone(),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl CondBr {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(term) }, 3);
Self {
condition: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
true_dest: func_ctx
.bb_names
.get(unsafe { &op_to_bb(LLVMGetOperand(term, 2)) })
.expect("Failed to find true-destination bb in map")
.clone(),
false_dest: func_ctx
.bb_names
.get(unsafe { &op_to_bb(LLVMGetOperand(term, 1)) })
.expect("Failed to find false-destination in bb map")
.clone(),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl Switch {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
dests: {
let num_dests = unsafe { LLVMGetNumSuccessors(term) };
let dest_bbs = (1 ..= num_dests)
.map(|i| {
func_ctx
.bb_names
.get(unsafe { &LLVMGetSuccessor(term, i) })
.expect("Failed to find switch destination in map")
.clone()
});
let dest_vals = (1 .. num_dests).map(|i| {
Constant::from_llvm_ref(unsafe { LLVMGetOperand(term, 2 * i) }, ctx)
});
Iterator::zip(dest_vals, dest_bbs).collect()
},
default_dest: func_ctx
.bb_names
.get(unsafe { &LLVMGetSwitchDefaultDest(term) })
.expect("Failed to find switch default destination in map")
.clone(),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl IndirectBr {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
possible_dests: {
let num_dests = unsafe { LLVMGetNumSuccessors(term) };
(0 .. num_dests)
.map(|i| {
func_ctx
.bb_names
.get(unsafe { &LLVMGetSuccessor(term, i) })
.expect("Failed to find indirect branch destination in map")
.clone()
})
.collect()
},
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl Invoke {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
use crate::instruction::CallInfo;
let callinfo = CallInfo::from_llvm_ref(term, ctx, func_ctx);
Self {
function: callinfo.function,
arguments: callinfo.arguments,
return_attributes: callinfo.return_attributes,
result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
return_label: func_ctx
.bb_names
.get(unsafe { &LLVMGetNormalDest(term) })
.expect("Failed to find invoke return destination in map")
.clone(),
exception_label: func_ctx
.bb_names
.get(unsafe { &LLVMGetUnwindDest(term) })
.expect("Failed to find invoke exception destination in map")
.clone(),
function_attributes: callinfo.function_attributes,
calling_convention: callinfo.calling_convention,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl Resume {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
Self {
operand: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl Unreachable {
pub(crate) fn from_llvm_ref(term: LLVMValueRef) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(term) }, 0);
Self {
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl CleanupRet {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(term) }, 1);
Self {
cleanup_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
unwind_dest: {
let dest = unsafe { LLVMGetUnwindDest(term) };
if dest.is_null() {
None
} else {
Some(
func_ctx
.bb_names
.get(&dest)
.unwrap_or_else(|| {
let names: Vec<_> = func_ctx.bb_names.values().collect();
panic!(
"Failed to find unwind destination in map; have names {:?}",
names
)
})
.clone(),
)
}
},
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl CatchRet {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
catch_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
successor: func_ctx
.bb_names
.get(unsafe { &LLVMGetSuccessor(term, 0) })
.expect("Failed to find CatchRet successor in map")
.clone(),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
impl CatchSwitch {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
parent_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(term, 0) }, ctx, func_ctx),
catch_handlers: {
let num_handlers = unsafe { LLVMGetNumHandlers(term) };
let mut handlers: Vec<LLVMBasicBlockRef> =
Vec::with_capacity(num_handlers as usize);
unsafe {
LLVMGetHandlers(term, handlers.as_mut_ptr());
handlers.set_len(num_handlers as usize);
};
handlers
.into_iter()
.map(|h| {
func_ctx
.bb_names
.get(&h)
.expect("Failed to find catch handler in map")
.clone()
})
.collect()
},
default_unwind_dest: {
let dest = unsafe { LLVMGetUnwindDest(term) };
if dest.is_null() {
None
} else {
Some(func_ctx.bb_names.get(&dest)
.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) })
.clone()
)
}
},
result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl CallBr {
pub(crate) fn from_llvm_ref(
term: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
use crate::instruction::CallInfo;
let callinfo = CallInfo::from_llvm_ref(term, ctx, func_ctx);
Self {
function: callinfo.function,
arguments: callinfo.arguments,
return_attributes: callinfo.return_attributes,
result: Name::name_or_num(unsafe { get_value_name(term) }, &mut func_ctx.ctr),
return_label: func_ctx
.bb_names
.get(unsafe { &LLVMGetNormalDest(term) })
.expect("Failed to find invoke return destination in map")
.clone(),
other_labels: (),
function_attributes: callinfo.function_attributes,
calling_convention: callinfo.calling_convention,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(term),
}
}
}