use crate::constant::ConstantRef;
#[cfg(feature="llvm-9-or-greater")]
use crate::debugloc::{DebugLoc, HasDebugLoc};
use crate::function::{CallingConvention, FunctionAttribute, ParameterAttribute};
use crate::name::Name;
use crate::operand::Operand;
use crate::predicates::*;
use crate::types::{NamedStructDef, Type, TypeRef, Typed, Types};
use either::Either;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display};
#[derive(PartialEq, Clone, Debug)]
pub enum Instruction {
Add(Add),
Sub(Sub),
Mul(Mul),
UDiv(UDiv),
SDiv(SDiv),
URem(URem),
SRem(SRem),
And(And),
Or(Or),
Xor(Xor),
Shl(Shl),
LShr(LShr),
AShr(AShr),
FAdd(FAdd),
FSub(FSub),
FMul(FMul),
FDiv(FDiv),
FRem(FRem),
FNeg(FNeg),
ExtractElement(ExtractElement),
InsertElement(InsertElement),
ShuffleVector(ShuffleVector),
ExtractValue(ExtractValue),
InsertValue(InsertValue),
Alloca(Alloca),
Load(Load),
Store(Store),
Fence(Fence),
CmpXchg(CmpXchg),
AtomicRMW(AtomicRMW),
GetElementPtr(GetElementPtr),
Trunc(Trunc),
ZExt(ZExt),
SExt(SExt),
FPTrunc(FPTrunc),
FPExt(FPExt),
FPToUI(FPToUI),
FPToSI(FPToSI),
UIToFP(UIToFP),
SIToFP(SIToFP),
PtrToInt(PtrToInt),
IntToPtr(IntToPtr),
BitCast(BitCast),
AddrSpaceCast(AddrSpaceCast),
ICmp(ICmp),
FCmp(FCmp),
Phi(Phi),
Select(Select),
#[cfg(feature="llvm-10-or-greater")]
Freeze(Freeze),
Call(Call),
VAArg(VAArg),
LandingPad(LandingPad),
CatchPad(CatchPad),
CleanupPad(CleanupPad),
}
impl Typed for Instruction {
fn get_type(&self, types: &Types) -> TypeRef {
match self {
Instruction::Add(i) => types.type_of(i),
Instruction::Sub(i) => types.type_of(i),
Instruction::Mul(i) => types.type_of(i),
Instruction::UDiv(i) => types.type_of(i),
Instruction::SDiv(i) => types.type_of(i),
Instruction::URem(i) => types.type_of(i),
Instruction::SRem(i) => types.type_of(i),
Instruction::And(i) => types.type_of(i),
Instruction::Or(i) => types.type_of(i),
Instruction::Xor(i) => types.type_of(i),
Instruction::Shl(i) => types.type_of(i),
Instruction::LShr(i) => types.type_of(i),
Instruction::AShr(i) => types.type_of(i),
Instruction::FAdd(i) => types.type_of(i),
Instruction::FSub(i) => types.type_of(i),
Instruction::FMul(i) => types.type_of(i),
Instruction::FDiv(i) => types.type_of(i),
Instruction::FRem(i) => types.type_of(i),
Instruction::FNeg(i) => types.type_of(i),
Instruction::ExtractElement(i) => types.type_of(i),
Instruction::InsertElement(i) => types.type_of(i),
Instruction::ShuffleVector(i) => types.type_of(i),
Instruction::ExtractValue(i) => types.type_of(i),
Instruction::InsertValue(i) => types.type_of(i),
Instruction::Alloca(i) => types.type_of(i),
Instruction::Load(i) => types.type_of(i),
Instruction::Store(i) => types.type_of(i),
Instruction::Fence(i) => types.type_of(i),
Instruction::CmpXchg(i) => types.type_of(i),
Instruction::AtomicRMW(i) => types.type_of(i),
Instruction::GetElementPtr(i) => types.type_of(i),
Instruction::Trunc(i) => types.type_of(i),
Instruction::ZExt(i) => types.type_of(i),
Instruction::SExt(i) => types.type_of(i),
Instruction::FPTrunc(i) => types.type_of(i),
Instruction::FPExt(i) => types.type_of(i),
Instruction::FPToUI(i) => types.type_of(i),
Instruction::FPToSI(i) => types.type_of(i),
Instruction::UIToFP(i) => types.type_of(i),
Instruction::SIToFP(i) => types.type_of(i),
Instruction::PtrToInt(i) => types.type_of(i),
Instruction::IntToPtr(i) => types.type_of(i),
Instruction::BitCast(i) => types.type_of(i),
Instruction::AddrSpaceCast(i) => types.type_of(i),
Instruction::ICmp(i) => types.type_of(i),
Instruction::FCmp(i) => types.type_of(i),
Instruction::Phi(i) => types.type_of(i),
Instruction::Select(i) => types.type_of(i),
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(i) => types.type_of(i),
Instruction::Call(i) => types.type_of(i),
Instruction::VAArg(i) => types.type_of(i),
Instruction::LandingPad(i) => types.type_of(i),
Instruction::CatchPad(i) => types.type_of(i),
Instruction::CleanupPad(i) => types.type_of(i),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl HasDebugLoc for Instruction {
fn get_debug_loc(&self) -> &Option<DebugLoc> {
match self {
Instruction::Add(i) => i.get_debug_loc(),
Instruction::Sub(i) => i.get_debug_loc(),
Instruction::Mul(i) => i.get_debug_loc(),
Instruction::UDiv(i) => i.get_debug_loc(),
Instruction::SDiv(i) => i.get_debug_loc(),
Instruction::URem(i) => i.get_debug_loc(),
Instruction::SRem(i) => i.get_debug_loc(),
Instruction::And(i) => i.get_debug_loc(),
Instruction::Or(i) => i.get_debug_loc(),
Instruction::Xor(i) => i.get_debug_loc(),
Instruction::Shl(i) => i.get_debug_loc(),
Instruction::LShr(i) => i.get_debug_loc(),
Instruction::AShr(i) => i.get_debug_loc(),
Instruction::FAdd(i) => i.get_debug_loc(),
Instruction::FSub(i) => i.get_debug_loc(),
Instruction::FMul(i) => i.get_debug_loc(),
Instruction::FDiv(i) => i.get_debug_loc(),
Instruction::FRem(i) => i.get_debug_loc(),
Instruction::FNeg(i) => i.get_debug_loc(),
Instruction::ExtractElement(i) => i.get_debug_loc(),
Instruction::InsertElement(i) => i.get_debug_loc(),
Instruction::ShuffleVector(i) => i.get_debug_loc(),
Instruction::ExtractValue(i) => i.get_debug_loc(),
Instruction::InsertValue(i) => i.get_debug_loc(),
Instruction::Alloca(i) => i.get_debug_loc(),
Instruction::Load(i) => i.get_debug_loc(),
Instruction::Store(i) => i.get_debug_loc(),
Instruction::Fence(i) => i.get_debug_loc(),
Instruction::CmpXchg(i) => i.get_debug_loc(),
Instruction::AtomicRMW(i) => i.get_debug_loc(),
Instruction::GetElementPtr(i) => i.get_debug_loc(),
Instruction::Trunc(i) => i.get_debug_loc(),
Instruction::ZExt(i) => i.get_debug_loc(),
Instruction::SExt(i) => i.get_debug_loc(),
Instruction::FPTrunc(i) => i.get_debug_loc(),
Instruction::FPExt(i) => i.get_debug_loc(),
Instruction::FPToUI(i) => i.get_debug_loc(),
Instruction::FPToSI(i) => i.get_debug_loc(),
Instruction::UIToFP(i) => i.get_debug_loc(),
Instruction::SIToFP(i) => i.get_debug_loc(),
Instruction::PtrToInt(i) => i.get_debug_loc(),
Instruction::IntToPtr(i) => i.get_debug_loc(),
Instruction::BitCast(i) => i.get_debug_loc(),
Instruction::AddrSpaceCast(i) => i.get_debug_loc(),
Instruction::ICmp(i) => i.get_debug_loc(),
Instruction::FCmp(i) => i.get_debug_loc(),
Instruction::Phi(i) => i.get_debug_loc(),
Instruction::Select(i) => i.get_debug_loc(),
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(i) => i.get_debug_loc(),
Instruction::Call(i) => i.get_debug_loc(),
Instruction::VAArg(i) => i.get_debug_loc(),
Instruction::LandingPad(i) => i.get_debug_loc(),
Instruction::CatchPad(i) => i.get_debug_loc(),
Instruction::CleanupPad(i) => i.get_debug_loc(),
}
}
}
impl Instruction {
pub fn try_get_result(&self) -> Option<&Name> {
match self {
Instruction::Add(i) => Some(&i.dest),
Instruction::Sub(i) => Some(&i.dest),
Instruction::Mul(i) => Some(&i.dest),
Instruction::UDiv(i) => Some(&i.dest),
Instruction::SDiv(i) => Some(&i.dest),
Instruction::URem(i) => Some(&i.dest),
Instruction::SRem(i) => Some(&i.dest),
Instruction::And(i) => Some(&i.dest),
Instruction::Or(i) => Some(&i.dest),
Instruction::Xor(i) => Some(&i.dest),
Instruction::Shl(i) => Some(&i.dest),
Instruction::LShr(i) => Some(&i.dest),
Instruction::AShr(i) => Some(&i.dest),
Instruction::FAdd(i) => Some(&i.dest),
Instruction::FSub(i) => Some(&i.dest),
Instruction::FMul(i) => Some(&i.dest),
Instruction::FDiv(i) => Some(&i.dest),
Instruction::FRem(i) => Some(&i.dest),
Instruction::FNeg(i) => Some(&i.dest),
Instruction::ExtractElement(i) => Some(&i.dest),
Instruction::InsertElement(i) => Some(&i.dest),
Instruction::ShuffleVector(i) => Some(&i.dest),
Instruction::ExtractValue(i) => Some(&i.dest),
Instruction::InsertValue(i) => Some(&i.dest),
Instruction::Alloca(i) => Some(&i.dest),
Instruction::Load(i) => Some(&i.dest),
Instruction::Store(_) => None,
Instruction::Fence(_) => None,
Instruction::CmpXchg(i) => Some(&i.dest),
Instruction::AtomicRMW(i) => Some(&i.dest),
Instruction::GetElementPtr(i) => Some(&i.dest),
Instruction::Trunc(i) => Some(&i.dest),
Instruction::ZExt(i) => Some(&i.dest),
Instruction::SExt(i) => Some(&i.dest),
Instruction::FPTrunc(i) => Some(&i.dest),
Instruction::FPExt(i) => Some(&i.dest),
Instruction::FPToUI(i) => Some(&i.dest),
Instruction::FPToSI(i) => Some(&i.dest),
Instruction::UIToFP(i) => Some(&i.dest),
Instruction::SIToFP(i) => Some(&i.dest),
Instruction::PtrToInt(i) => Some(&i.dest),
Instruction::IntToPtr(i) => Some(&i.dest),
Instruction::BitCast(i) => Some(&i.dest),
Instruction::AddrSpaceCast(i) => Some(&i.dest),
Instruction::ICmp(i) => Some(&i.dest),
Instruction::FCmp(i) => Some(&i.dest),
Instruction::Phi(i) => Some(&i.dest),
Instruction::Select(i) => Some(&i.dest),
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(i) => Some(&i.dest),
Instruction::Call(i) => i.dest.as_ref(),
Instruction::VAArg(i) => Some(&i.dest),
Instruction::LandingPad(i) => Some(&i.dest),
Instruction::CatchPad(i) => Some(&i.dest),
Instruction::CleanupPad(i) => Some(&i.dest),
}
}
pub fn is_atomic(&self) -> bool {
match self {
Instruction::Add(_) => false,
Instruction::Sub(_) => false,
Instruction::Mul(_) => false,
Instruction::UDiv(_) => false,
Instruction::SDiv(_) => false,
Instruction::URem(_) => false,
Instruction::SRem(_) => false,
Instruction::And(_) => false,
Instruction::Or(_) => false,
Instruction::Xor(_) => false,
Instruction::Shl(_) => false,
Instruction::LShr(_) => false,
Instruction::AShr(_) => false,
Instruction::FAdd(_) => false,
Instruction::FSub(_) => false,
Instruction::FMul(_) => false,
Instruction::FDiv(_) => false,
Instruction::FRem(_) => false,
Instruction::FNeg(_) => false,
Instruction::ExtractElement(_) => false,
Instruction::InsertElement(_) => false,
Instruction::ShuffleVector(_) => false,
Instruction::ExtractValue(_) => false,
Instruction::InsertValue(_) => false,
Instruction::Alloca(_) => false,
Instruction::Load(i) => i.atomicity.is_some(),
Instruction::Store(i) => i.atomicity.is_some(),
Instruction::Fence(_) => true,
Instruction::CmpXchg(_) => true,
Instruction::AtomicRMW(_) => true,
Instruction::GetElementPtr(_) => false,
Instruction::Trunc(_) => false,
Instruction::ZExt(_) => false,
Instruction::SExt(_) => false,
Instruction::FPTrunc(_) => false,
Instruction::FPExt(_) => false,
Instruction::FPToUI(_) => false,
Instruction::FPToSI(_) => false,
Instruction::UIToFP(_) => false,
Instruction::SIToFP(_) => false,
Instruction::PtrToInt(_) => false,
Instruction::IntToPtr(_) => false,
Instruction::BitCast(_) => false,
Instruction::AddrSpaceCast(_) => false,
Instruction::ICmp(_) => false,
Instruction::FCmp(_) => false,
Instruction::Phi(_) => false,
Instruction::Select(_) => false,
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(_) => false,
Instruction::Call(_) => false,
Instruction::VAArg(_) => false,
Instruction::LandingPad(_) => false,
Instruction::CatchPad(_) => false,
Instruction::CleanupPad(_) => false,
}
}
}
pub trait HasResult: Debug + Typed {
fn get_result(&self) -> &Name;
}
pub trait UnaryOp: HasResult {
fn get_operand(&self) -> &Operand;
}
pub trait BinaryOp: HasResult {
fn get_operand0(&self) -> &Operand;
fn get_operand1(&self) -> &Operand;
}
pub mod groups;
impl Instruction {
pub fn is_binary_op(&self) -> bool {
match self {
Instruction::Add(_) => true,
Instruction::Sub(_) => true,
Instruction::Mul(_) => true,
Instruction::UDiv(_) => true,
Instruction::SDiv(_) => true,
Instruction::URem(_) => true,
Instruction::SRem(_) => true,
Instruction::And(_) => true,
Instruction::Or(_) => true,
Instruction::Xor(_) => true,
Instruction::Shl(_) => true,
Instruction::LShr(_) => true,
Instruction::AShr(_) => true,
Instruction::FAdd(_) => true,
Instruction::FSub(_) => true,
Instruction::FMul(_) => true,
Instruction::FDiv(_) => true,
Instruction::FRem(_) => true,
_ => false,
}
}
pub fn is_unary_op(&self) -> bool {
match self {
Instruction::AddrSpaceCast(_) => true,
Instruction::BitCast(_) => true,
Instruction::FNeg(_) => true,
Instruction::FPExt(_) => true,
Instruction::FPToSI(_) => true,
Instruction::FPToUI(_) => true,
Instruction::FPTrunc(_) => true,
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(_) => true,
Instruction::IntToPtr(_) => true,
Instruction::PtrToInt(_) => true,
Instruction::SExt(_) => true,
Instruction::SIToFP(_) => true,
Instruction::Trunc(_) => true,
Instruction::UIToFP(_) => true,
Instruction::ZExt(_) => true,
_ => false,
}
}
}
impl Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Instruction::Add(i) => write!(f, "{}", i),
Instruction::Sub(i) => write!(f, "{}", i),
Instruction::Mul(i) => write!(f, "{}", i),
Instruction::UDiv(i) => write!(f, "{}", i),
Instruction::SDiv(i) => write!(f, "{}", i),
Instruction::URem(i) => write!(f, "{}", i),
Instruction::SRem(i) => write!(f, "{}", i),
Instruction::And(i) => write!(f, "{}", i),
Instruction::Or(i) => write!(f, "{}", i),
Instruction::Xor(i) => write!(f, "{}", i),
Instruction::Shl(i) => write!(f, "{}", i),
Instruction::LShr(i) => write!(f, "{}", i),
Instruction::AShr(i) => write!(f, "{}", i),
Instruction::FAdd(i) => write!(f, "{}", i),
Instruction::FSub(i) => write!(f, "{}", i),
Instruction::FMul(i) => write!(f, "{}", i),
Instruction::FDiv(i) => write!(f, "{}", i),
Instruction::FRem(i) => write!(f, "{}", i),
Instruction::FNeg(i) => write!(f, "{}", i),
Instruction::ExtractElement(i) => write!(f, "{}", i),
Instruction::InsertElement(i) => write!(f, "{}", i),
Instruction::ShuffleVector(i) => write!(f, "{}", i),
Instruction::ExtractValue(i) => write!(f, "{}", i),
Instruction::InsertValue(i) => write!(f, "{}", i),
Instruction::Alloca(i) => write!(f, "{}", i),
Instruction::Load(i) => write!(f, "{}", i),
Instruction::Store(i) => write!(f, "{}", i),
Instruction::Fence(i) => write!(f, "{}", i),
Instruction::CmpXchg(i) => write!(f, "{}", i),
Instruction::AtomicRMW(i) => write!(f, "{}", i),
Instruction::GetElementPtr(i) => write!(f, "{}", i),
Instruction::Trunc(i) => write!(f, "{}", i),
Instruction::ZExt(i) => write!(f, "{}", i),
Instruction::SExt(i) => write!(f, "{}", i),
Instruction::FPTrunc(i) => write!(f, "{}", i),
Instruction::FPExt(i) => write!(f, "{}", i),
Instruction::FPToUI(i) => write!(f, "{}", i),
Instruction::FPToSI(i) => write!(f, "{}", i),
Instruction::UIToFP(i) => write!(f, "{}", i),
Instruction::SIToFP(i) => write!(f, "{}", i),
Instruction::PtrToInt(i) => write!(f, "{}", i),
Instruction::IntToPtr(i) => write!(f, "{}", i),
Instruction::BitCast(i) => write!(f, "{}", i),
Instruction::AddrSpaceCast(i) => write!(f, "{}", i),
Instruction::ICmp(i) => write!(f, "{}", i),
Instruction::FCmp(i) => write!(f, "{}", i),
Instruction::Phi(i) => write!(f, "{}", i),
Instruction::Select(i) => write!(f, "{}", i),
#[cfg(feature="llvm-10-or-greater")]
Instruction::Freeze(i) => write!(f, "{}", i),
Instruction::Call(i) => write!(f, "{}", i),
Instruction::VAArg(i) => write!(f, "{}", i),
Instruction::LandingPad(i) => write!(f, "{}", i),
Instruction::CatchPad(i) => write!(f, "{}", i),
Instruction::CleanupPad(i) => write!(f, "{}", i),
}
}
}
macro_rules! impl_inst {
($inst:ty, $id:ident) => {
impl From<$inst> for Instruction {
fn from(inst: $inst) -> Instruction {
Instruction::$id(inst)
}
}
impl TryFrom<Instruction> for $inst {
type Error = &'static str;
fn try_from(inst: Instruction) -> Result<Self, Self::Error> {
match inst {
Instruction::$id(inst) => Ok(inst),
_ => Err("Instruction is not of requested type"),
}
}
}
#[cfg(feature="llvm-9-or-greater")]
impl HasDebugLoc for $inst {
fn get_debug_loc(&self) -> &Option<DebugLoc> {
&self.debugloc
}
}
};
}
macro_rules! impl_hasresult {
($inst:ty) => {
impl HasResult for $inst {
fn get_result(&self) -> &Name {
&self.dest
}
}
};
}
macro_rules! impl_unop {
($inst:ty) => {
impl_hasresult!($inst);
impl UnaryOp for $inst {
fn get_operand(&self) -> &Operand {
&self.operand
}
}
};
}
macro_rules! impl_binop {
($inst:ty, $id:ident, $dispname:expr) => {
impl_hasresult!($inst);
impl BinaryOp for $inst {
fn get_operand0(&self) -> &Operand {
&self.operand0
}
fn get_operand1(&self) -> &Operand {
&self.operand1
}
}
impl From<$inst> for groups::BinaryOp {
fn from(inst: $inst) -> Self {
groups::BinaryOp::$id(inst)
}
}
impl TryFrom<groups::BinaryOp> for $inst {
type Error = &'static str;
fn try_from(bo: groups::BinaryOp) -> Result<Self, Self::Error> {
match bo {
groups::BinaryOp::$id(i) => Ok(i),
_ => Err("BinaryOp is not of requested type"),
}
}
}
impl Display for $inst {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {} {}, {}",
&self.dest, $dispname, &self.operand0, &self.operand1,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
};
}
macro_rules! unop_same_type {
($inst:ty, $dispname:expr) => {
impl_unop!($inst);
impl Typed for $inst {
fn get_type(&self, types: &Types) -> TypeRef {
types.type_of(self.get_operand())
}
}
impl Display for $inst {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {} {}", &self.dest, $dispname, &self.operand)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
};
}
macro_rules! unop_explicitly_typed {
($inst:ty, $dispname:expr) => {
impl_unop!($inst);
explicitly_typed!($inst);
impl Display for $inst {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {} {} to {}",
&self.dest, $dispname, &self.operand, &self.to_type,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
};
}
macro_rules! binop_same_type {
($inst:ty, $id:ident, $dispname:expr) => {
impl_binop!($inst, $id, $dispname);
impl Typed for $inst {
fn get_type(&self, types: &Types) -> TypeRef {
let ty = types.type_of(self.get_operand0());
debug_assert_eq!(ty, types.type_of(self.get_operand1()));
ty
}
}
};
}
macro_rules! binop_left_type {
($inst:ty, $id:ident, $dispname:expr) => {
impl_binop!($inst, $id, $dispname);
impl Typed for $inst {
fn get_type(&self, types: &Types) -> TypeRef {
types.type_of(self.get_operand0())
}
}
};
}
macro_rules! explicitly_typed {
($inst:ty) => {
impl Typed for $inst {
fn get_type(&self, _types: &Types) -> TypeRef {
self.to_type.clone()
}
}
};
}
macro_rules! void_typed {
($inst:ty) => {
impl Typed for $inst {
fn get_type(&self, types: &Types) -> TypeRef {
types.void()
}
}
};
}
#[derive(PartialEq, Clone, Debug)]
pub struct Add {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Add, Add);
binop_same_type!(Add, Add, "add");
#[derive(PartialEq, Clone, Debug)]
pub struct Sub {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Sub, Sub);
binop_same_type!(Sub, Sub, "sub");
#[derive(PartialEq, Clone, Debug)]
pub struct Mul {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Mul, Mul);
binop_same_type!(Mul, Mul, "mul");
#[derive(PartialEq, Clone, Debug)]
pub struct UDiv {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(UDiv, UDiv);
binop_same_type!(UDiv, UDiv, "udiv");
#[derive(PartialEq, Clone, Debug)]
pub struct SDiv {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(SDiv, SDiv);
binop_same_type!(SDiv, SDiv, "sdiv");
#[derive(PartialEq, Clone, Debug)]
pub struct URem {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(URem, URem);
binop_same_type!(URem, URem, "urem");
#[derive(PartialEq, Clone, Debug)]
pub struct SRem {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(SRem, SRem);
binop_same_type!(SRem, SRem, "srem");
#[derive(PartialEq, Clone, Debug)]
pub struct And {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(And, And);
binop_same_type!(And, And, "and");
#[derive(PartialEq, Clone, Debug)]
pub struct Or {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Or, Or);
binop_same_type!(Or, Or, "or");
#[derive(PartialEq, Clone, Debug)]
pub struct Xor {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Xor, Xor);
binop_same_type!(Xor, Xor, "xor");
#[derive(PartialEq, Clone, Debug)]
pub struct Shl {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Shl, Shl);
binop_left_type!(Shl, Shl, "shl");
#[derive(PartialEq, Clone, Debug)]
pub struct LShr {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(LShr, LShr);
binop_left_type!(LShr, LShr, "lshr");
#[derive(PartialEq, Clone, Debug)]
pub struct AShr {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(AShr, AShr);
binop_left_type!(AShr, AShr, "ashr");
#[derive(PartialEq, Clone, Debug)]
pub struct FAdd {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FAdd, FAdd);
binop_same_type!(FAdd, FAdd, "fadd");
#[derive(PartialEq, Clone, Debug)]
pub struct FSub {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FSub, FSub);
binop_same_type!(FSub, FSub, "fsub");
#[derive(PartialEq, Clone, Debug)]
pub struct FMul {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FMul, FMul);
binop_same_type!(FMul, FMul, "fmul");
#[derive(PartialEq, Clone, Debug)]
pub struct FDiv {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FDiv, FDiv);
binop_same_type!(FDiv, FDiv, "fdiv");
#[derive(PartialEq, Clone, Debug)]
pub struct FRem {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FRem, FRem);
binop_same_type!(FRem, FRem, "frem");
#[derive(PartialEq, Clone, Debug)]
pub struct FNeg {
pub operand: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FNeg, FNeg);
unop_same_type!(FNeg, "fneg");
#[derive(PartialEq, Clone, Debug)]
pub struct ExtractElement {
pub vector: Operand,
pub index: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(ExtractElement, ExtractElement);
impl_hasresult!(ExtractElement);
impl Typed for ExtractElement {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.vector).as_ref() {
Type::VectorType { element_type, .. } => element_type.clone(),
ty => panic!(
"Expected an ExtractElement vector to be VectorType, got {:?}",
ty
),
}
}
}
impl Display for ExtractElement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = extractelement {}, {}",
&self.dest, &self.vector, &self.index,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct InsertElement {
pub vector: Operand,
pub element: Operand,
pub index: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(InsertElement, InsertElement);
impl_hasresult!(InsertElement);
impl Typed for InsertElement {
fn get_type(&self, types: &Types) -> TypeRef {
types.type_of(&self.vector)
}
}
impl Display for InsertElement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = insertelement {}, {}, {}",
&self.dest, &self.vector, &self.element, &self.index,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct ShuffleVector {
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
pub mask: ConstantRef,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(ShuffleVector, ShuffleVector);
impl_hasresult!(ShuffleVector);
impl Typed for ShuffleVector {
fn get_type(&self, types: &Types) -> TypeRef {
let ty = types.type_of(&self.operand0);
debug_assert_eq!(ty, types.type_of(&self.operand1));
match ty.as_ref() {
Type::VectorType { element_type, .. } => match types.type_of(&self.mask).as_ref() {
#[cfg(feature="llvm-11-or-greater")]
Type::VectorType { num_elements, scalable, .. } => {
types.vector_of(element_type.clone(), *num_elements, *scalable)
},
#[cfg(feature="llvm-10-or-lower")]
Type::VectorType { num_elements, .. } => {
types.vector_of(element_type.clone(), *num_elements)
},
ty => panic!(
"Expected a ShuffleVector mask to be VectorType, got {:?}",
ty
),
},
_ => panic!(
"Expected a ShuffleVector operand to be VectorType, got {:?}",
ty
),
}
}
}
impl Display for ShuffleVector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = shufflevector {}, {}, {}",
&self.dest, &self.operand0, &self.operand1, &self.mask,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct ExtractValue {
pub aggregate: Operand,
pub indices: Vec<u32>,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(ExtractValue, ExtractValue);
impl_hasresult!(ExtractValue);
impl Typed for ExtractValue {
fn get_type(&self, types: &Types) -> TypeRef {
ev_type(types.type_of(&self.aggregate), self.indices.iter().copied())
}
}
fn ev_type(cur_type: TypeRef, mut indices: impl Iterator<Item = u32>) -> TypeRef {
match indices.next() {
None => cur_type,
Some(index) => match cur_type.as_ref() {
Type::ArrayType { element_type, .. } => ev_type(element_type.clone(), indices),
Type::StructType { element_types, .. } => ev_type(
element_types
.get(index as usize)
.expect("ExtractValue index out of range")
.clone(),
indices,
),
_ => panic!(
"ExtractValue from something that's not ArrayType or StructType; its type is {:?}",
cur_type
),
},
}
}
impl Display for ExtractValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = extractvalue {}, {}",
&self.dest,
&self.aggregate,
&self.indices.get(0).expect("ExtractValue with no indices")
)?;
for idx in &self.indices[1 ..] {
write!(f, ", {}", idx)?;
}
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct InsertValue {
pub aggregate: Operand,
pub element: Operand,
pub indices: Vec<u32>,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(InsertValue, InsertValue);
impl_hasresult!(InsertValue);
impl Typed for InsertValue {
fn get_type(&self, types: &Types) -> TypeRef {
types.type_of(&self.aggregate)
}
}
impl Display for InsertValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = insertvalue {}, {}, {}",
&self.dest,
&self.aggregate,
&self.element,
&self.indices.get(0).expect("InsertValue with no indices"),
)?;
for idx in &self.indices[1 ..] {
write!(f, ", {}", idx)?;
}
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Alloca {
pub allocated_type: TypeRef,
pub num_elements: Operand,
pub dest: Name,
pub alignment: u32,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Alloca, Alloca);
impl_hasresult!(Alloca);
impl Typed for Alloca {
fn get_type(&self, types: &Types) -> TypeRef {
types.pointer_to(self.allocated_type.clone())
}
}
impl Display for Alloca {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = alloca {}",
&self.dest, &self.allocated_type,
)?;
if let Some(Constant::Int { value: 1, .. }) = self.num_elements.as_constant() {
} else {
write!(f, ", {}", &self.num_elements)?;
}
write!(f, ", align {}", &self.alignment)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Load {
pub address: Operand,
pub dest: Name,
pub volatile: bool,
pub atomicity: Option<Atomicity>,
pub alignment: u32,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Load, Load);
impl_hasresult!(Load);
impl Typed for Load {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.address).as_ref() {
Type::PointerType { pointee_type, .. } => pointee_type.clone(),
ty => panic!("Expected a load address to be PointerType, got {:?}", ty),
}
}
}
impl Display for Load {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = load ", &self.dest)?;
if self.atomicity.is_some() {
write!(f, "atomic ")?;
}
if self.volatile {
write!(f, "volatile ")?;
}
write!(f, "{}", &self.address)?;
if let Some(a) = &self.atomicity {
write!(f, " {}", a)?;
}
write!(f, ", align {}", &self.alignment)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Store {
pub address: Operand,
pub value: Operand,
pub volatile: bool,
pub atomicity: Option<Atomicity>,
pub alignment: u32,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Store, Store);
void_typed!(Store);
impl Display for Store {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "store ")?;
if self.atomicity.is_some() {
write!(f, "atomic ")?;
}
if self.volatile {
write!(f, "volatile ")?;
}
write!(f, "{}, {}", &self.value, &self.address)?;
if let Some(a) = &self.atomicity {
write!(f, " {}", a)?;
}
write!(f, ", align {}", &self.alignment)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Fence {
pub atomicity: Atomicity,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Fence, Fence);
void_typed!(Fence);
impl Display for Fence {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "fence {}", &self.atomicity)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CmpXchg {
pub address: Operand,
pub expected: Operand,
pub replacement: Operand,
pub dest: Name,
pub volatile: bool,
pub atomicity: Atomicity,
pub failure_memory_ordering: MemoryOrdering,
#[cfg(feature="llvm-10-or-greater")]
pub weak: bool,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(CmpXchg, CmpXchg);
impl_hasresult!(CmpXchg);
impl Typed for CmpXchg {
fn get_type(&self, types: &Types) -> TypeRef {
let ty = types.type_of(&self.expected);
debug_assert_eq!(ty, types.type_of(&self.replacement));
types.struct_of(vec![ty, types.bool()], false)
}
}
impl Display for CmpXchg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = cmpxchg ", &self.dest)?;
#[cfg(feature="llvm-10-or-greater")]
if self.weak {
write!(f, "weak ")?;
}
if self.volatile {
write!(f, "volatile ")?;
}
write!(f, "{}, {}, {} {} {}",
&self.address,
&self.expected,
&self.replacement,
&self.atomicity,
&self.failure_memory_ordering,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct AtomicRMW {
#[cfg(feature="llvm-10-or-greater")]
pub operation: RMWBinOp,
pub address: Operand,
pub value: Operand,
pub dest: Name,
pub volatile: bool,
pub atomicity: Atomicity,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(AtomicRMW, AtomicRMW);
impl_hasresult!(AtomicRMW);
impl Typed for AtomicRMW {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.address).as_ref() {
Type::PointerType { pointee_type, .. } => pointee_type.clone(),
ty => panic!(
"Expected an AtomicRMW address to be PointerType, got {:?}",
ty
),
}
}
}
impl Display for AtomicRMW {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = atomicrmw ", &self.dest)?;
if self.volatile {
write!(f, "volatile ")?;
}
#[cfg(feature="llvm-10-or-greater")]
write!(f, "{} ", &self.operation)?;
write!(f, "{}, {} {}", &self.address, &self.value, &self.atomicity)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct GetElementPtr {
pub address: Operand,
pub indices: Vec<Operand>,
pub dest: Name,
pub in_bounds: bool,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(GetElementPtr, GetElementPtr);
impl_hasresult!(GetElementPtr);
impl Typed for GetElementPtr {
fn get_type(&self, types: &Types) -> TypeRef {
gep_type(types.type_of(&self.address), self.indices.iter(), types)
}
}
fn gep_type<'o>(
cur_type: TypeRef,
mut indices: impl Iterator<Item = &'o Operand>,
types: &Types,
) -> TypeRef {
if let Type::NamedStructType { name } = cur_type.as_ref() {
match types.named_struct_def(name) {
None => panic!("Named struct without a definition (name {:?})", name),
Some(NamedStructDef::Opaque) => {
panic!("GEP on an opaque struct type (name {:?})", name)
},
Some(NamedStructDef::Defined(ty)) => {
return gep_type(ty.clone(), indices, types);
},
}
}
match indices.next() {
None => types.pointer_to(cur_type),
Some(index) => match cur_type.as_ref() {
Type::PointerType { pointee_type, .. } => gep_type(pointee_type.clone(), indices, types),
Type::VectorType { element_type, .. } => gep_type(element_type.clone(), indices, types),
Type::ArrayType { element_type, .. } => gep_type(element_type.clone(), indices, types),
Type::StructType { element_types, .. } => {
if let Operand::ConstantOperand(cref) = index {
if let Constant::Int { value, .. } = cref.as_ref() {
gep_type(element_types.get(*value as usize).cloned().expect("GEP index out of range"), indices, types)
} else {
panic!("Expected GEP index on a struct to be a Constant::Int; got {:?}", cref)
}
} else {
panic!("Expected GEP index on a struct to be a Operand::ConstantOperand(Constant::Int); got {:?}", index)
}
},
Type::NamedStructType { .. } => panic!("This case should have been handled above"),
_ => panic!("Expected GEP base type to be a PointerType, VectorType, ArrayType, StructType, or NamedStructType; got {:?}", cur_type),
}
}
}
impl Display for GetElementPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = getelementptr ", &self.dest)?;
if self.in_bounds {
write!(f, "inbounds ")?;
}
write!(f, "{}", &self.address)?;
for idx in &self.indices {
write!(f, ", {}", idx)?;
}
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Trunc {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Trunc, Trunc);
unop_explicitly_typed!(Trunc, "trunc");
#[derive(PartialEq, Clone, Debug)]
pub struct ZExt {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(ZExt, ZExt);
unop_explicitly_typed!(ZExt, "zext");
#[derive(PartialEq, Clone, Debug)]
pub struct SExt {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(SExt, SExt);
unop_explicitly_typed!(SExt, "sext");
#[derive(PartialEq, Clone, Debug)]
pub struct FPTrunc {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FPTrunc, FPTrunc);
unop_explicitly_typed!(FPTrunc, "fptrunc");
#[derive(PartialEq, Clone, Debug)]
pub struct FPExt {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FPExt, FPExt);
unop_explicitly_typed!(FPExt, "fpext");
#[derive(PartialEq, Clone, Debug)]
pub struct FPToUI {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FPToUI, FPToUI);
unop_explicitly_typed!(FPToUI, "fptoui");
#[derive(PartialEq, Clone, Debug)]
pub struct FPToSI {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FPToSI, FPToSI);
unop_explicitly_typed!(FPToSI, "fptosi");
#[derive(PartialEq, Clone, Debug)]
pub struct UIToFP {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(UIToFP, UIToFP);
unop_explicitly_typed!(UIToFP, "uitofp");
#[derive(PartialEq, Clone, Debug)]
pub struct SIToFP {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(SIToFP, SIToFP);
unop_explicitly_typed!(SIToFP, "sitofp");
#[derive(PartialEq, Clone, Debug)]
pub struct PtrToInt {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(PtrToInt, PtrToInt);
unop_explicitly_typed!(PtrToInt, "ptrtoint");
#[derive(PartialEq, Clone, Debug)]
pub struct IntToPtr {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(IntToPtr, IntToPtr);
unop_explicitly_typed!(IntToPtr, "inttoptr");
#[derive(PartialEq, Clone, Debug)]
pub struct BitCast {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(BitCast, BitCast);
unop_explicitly_typed!(BitCast, "bitcast");
#[derive(PartialEq, Clone, Debug)]
pub struct AddrSpaceCast {
pub operand: Operand,
pub to_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(AddrSpaceCast, AddrSpaceCast);
unop_explicitly_typed!(AddrSpaceCast, "addrspacecast");
#[derive(PartialEq, Clone, Debug)]
pub struct ICmp {
pub predicate: IntPredicate,
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(ICmp, ICmp);
impl_hasresult!(ICmp);
impl Typed for ICmp {
fn get_type(&self, types: &Types) -> TypeRef {
let ty = types.type_of(&self.operand0);
debug_assert_eq!(ty, types.type_of(&self.operand1));
match ty.as_ref() {
#[cfg(feature="llvm-11-or-greater")]
Type::VectorType { num_elements, scalable, .. } => {
types.vector_of(types.bool(), *num_elements, *scalable)
},
#[cfg(feature="llvm-10-or-lower")]
Type::VectorType { num_elements, .. } => {
types.vector_of(types.bool(), *num_elements)
},
_ => types.bool(),
}
}
}
impl Display for ICmp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = icmp {} {}, {}",
&self.dest,
&self.predicate,
&self.operand0,
&self.operand1,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct FCmp {
pub predicate: FPPredicate,
pub operand0: Operand,
pub operand1: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(FCmp, FCmp);
impl_hasresult!(FCmp);
impl Typed for FCmp {
fn get_type(&self, types: &Types) -> TypeRef {
let ty = types.type_of(&self.operand0);
debug_assert_eq!(ty, types.type_of(&self.operand1));
match ty.as_ref() {
#[cfg(feature="llvm-11-or-greater")]
Type::VectorType { num_elements, scalable, .. } => {
types.vector_of(types.bool(), *num_elements, *scalable)
},
#[cfg(feature="llvm-10-or-lower")]
Type::VectorType { num_elements, .. } => {
types.vector_of(types.bool(), *num_elements)
},
_ => types.bool(),
}
}
}
impl Display for FCmp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = fcmp {} {}, {}",
&self.dest, &self.predicate, &self.operand0, &self.operand1,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Phi {
pub incoming_values: Vec<(Operand, Name)>,
pub dest: Name,
pub to_type: TypeRef,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Phi, Phi);
impl_hasresult!(Phi);
explicitly_typed!(Phi);
impl Display for Phi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (first_val, first_label) = &self
.incoming_values
.get(0)
.expect("Phi with no incoming values");
write!(f, "{} = phi {} [ {}, {} ]",
&self.dest, &self.to_type, first_val, first_label,
)?;
for (val, label) in &self.incoming_values[1 ..] {
write!(f, ", [ {}, {} ]", val, label)?;
}
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Select {
pub condition: Operand,
pub true_value: Operand,
pub false_value: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Select, Select);
impl_hasresult!(Select);
impl Typed for Select {
fn get_type(&self, types: &Types) -> TypeRef {
let t = types.type_of(&self.true_value);
debug_assert_eq!(t, types.type_of(&self.false_value));
t
}
}
impl Display for Select {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = select {}, {}, {}",
&self.dest, &self.condition, &self.true_value, &self.false_value,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[cfg(feature="llvm-10-or-greater")]
#[derive(PartialEq, Clone, Debug)]
pub struct Freeze {
pub operand: Operand,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
#[cfg(feature="llvm-10-or-greater")]
impl_inst!(Freeze, Freeze);
#[cfg(feature="llvm-10-or-greater")]
unop_same_type!(Freeze, "freeze");
#[derive(PartialEq, Clone, Debug)]
pub struct Call {
pub function: Either<InlineAssembly, Operand>,
pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
pub return_attributes: Vec<ParameterAttribute>,
pub dest: Option<Name>,
pub function_attributes: Vec<FunctionAttribute>,
pub is_tail_call: bool,
pub calling_convention: CallingConvention,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(Call, Call);
impl Typed for Call {
fn get_type(&self, types: &Types) -> TypeRef {
match types.type_of(&self.function).as_ref() {
Type::PointerType { pointee_type, .. } => match pointee_type.as_ref() {
Type::FuncType { result_type, .. } => result_type.clone(),
ty => panic!("Expected Call's function argument to be of type pointer-to-function, got pointer-to-{:?}", ty),
},
ty => panic!("Expected Call's function argument to be of type pointer-to-function, got {:?}", ty),
}
}
}
impl Display for Call {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(dest) = &self.dest {
write!(f, "{} = ", dest)?;
}
if self.is_tail_call {
write!(f, "tail ")?;
}
write!(f, "call {}(",
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, ")")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct VAArg {
pub arg_list: Operand,
pub cur_type: TypeRef,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(VAArg, VAArg);
impl_hasresult!(VAArg);
impl Typed for VAArg {
fn get_type(&self, _types: &Types) -> TypeRef {
self.cur_type.clone()
}
}
impl Display for VAArg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = va_arg {}, {}",
&self.dest, &self.arg_list, &self.cur_type,
)?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct LandingPad {
pub result_type: TypeRef,
pub clauses: Vec<LandingPadClause>,
pub dest: Name,
pub cleanup: bool,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(LandingPad, LandingPad);
impl_hasresult!(LandingPad);
impl Typed for LandingPad {
fn get_type(&self, _types: &Types) -> TypeRef {
self.result_type.clone()
}
}
impl Display for LandingPad {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = landingpad {}", &self.dest, &self.result_type)?;
if self.cleanup {
write!(f, " cleanup")?;
}
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CatchPad {
pub catch_switch: Operand,
pub args: Vec<Operand>,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(CatchPad, CatchPad);
impl_hasresult!(CatchPad);
impl Typed for CatchPad {
fn get_type(&self, types: &Types) -> TypeRef {
types.token_type()
}
}
impl Display for CatchPad {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = catchpad within {} [",
&self.dest, &self.catch_switch,
)?;
for (i, arg) in self.args.iter().enumerate() {
if i == self.args.len() - 1 {
write!(f, "{}", arg)?;
} else {
write!(f, "{}, ", arg)?;
}
}
write!(f, "]")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct CleanupPad {
pub parent_pad: Operand,
pub args: Vec<Operand>,
pub dest: Name,
#[cfg(feature="llvm-9-or-greater")]
pub debugloc: Option<DebugLoc>,
}
impl_inst!(CleanupPad, CleanupPad);
impl_hasresult!(CleanupPad);
impl Typed for CleanupPad {
fn get_type(&self, types: &Types) -> TypeRef {
types.token_type()
}
}
impl Display for CleanupPad {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = cleanuppad within {} [",
&self.dest, &self.parent_pad,
)?;
for (i, arg) in self.args.iter().enumerate() {
if i == self.args.len() - 1 {
write!(f, "{}", arg)?;
} else {
write!(f, "{}, ", arg)?;
}
}
write!(f, "]")?;
#[cfg(feature="llvm-9-or-greater")]
if self.debugloc.is_some() {
write!(f, " (with debugloc)")?;
}
Ok(())
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum TailCallKind {
Tail,
MustTail,
NoTail,
}
#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(non_snake_case)]
pub struct FastMathFlags {
pub allow_reassoc: bool,
pub no_NaNs: bool,
pub no_Infs: bool,
pub no_signed_zeros: bool,
pub allow_reciprocal: bool,
pub allow_contract: bool,
pub approx_func: bool,
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Atomicity {
pub synch_scope: SynchronizationScope,
pub mem_ordering: MemoryOrdering,
}
impl Display for Atomicity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.synch_scope {
SynchronizationScope::SingleThread => write!(f, "syncscope(\"singlethread\") "),
SynchronizationScope::System => Ok(()),
}?;
write!(f, "{}", &self.mem_ordering)?;
Ok(())
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum SynchronizationScope {
SingleThread,
System,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum MemoryOrdering {
Unordered,
Monotonic,
Acquire,
Release,
AcquireRelease,
SequentiallyConsistent,
NotAtomic,
}
impl Display for MemoryOrdering {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MemoryOrdering::Unordered => write!(f, "unordered"),
MemoryOrdering::Monotonic => write!(f, "monotonic"),
MemoryOrdering::Acquire => write!(f, "acquire"),
MemoryOrdering::Release => write!(f, "release"),
MemoryOrdering::AcquireRelease => write!(f, "acq_rel"),
MemoryOrdering::SequentiallyConsistent => write!(f, "seq_cst"),
MemoryOrdering::NotAtomic => write!(f, "not_atomic"),
}
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InlineAssembly {
pub ty: TypeRef,
}
impl Typed for InlineAssembly {
fn get_type(&self, _types: &Types) -> TypeRef {
self.ty.clone()
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum RMWBinOp {
Xchg,
Add,
Sub,
And,
Nand,
Or,
Xor,
Max,
Min,
UMax,
UMin,
#[cfg(feature="llvm-10-or-greater")]
FAdd,
#[cfg(feature="llvm-10-or-greater")]
FSub,
}
impl Display for RMWBinOp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Xchg => write!(f, "xchg"),
Self::Add => write!(f, "add"),
Self::Sub => write!(f, "sub"),
Self::And => write!(f, "and"),
Self::Nand => write!(f, "nand"),
Self::Or => write!(f, "or"),
Self::Xor => write!(f, "xor"),
Self::Max => write!(f, "max"),
Self::Min => write!(f, "min"),
Self::UMax => write!(f, "umax"),
Self::UMin => write!(f, "umin"),
#[cfg(feature="llvm-10-or-greater")]
Self::FAdd => write!(f, "fadd"),
#[cfg(feature="llvm-10-or-greater")]
Self::FSub => write!(f, "fsub"),
}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct LandingPadClause {}
use crate::constant::Constant;
use crate::from_llvm::*;
use crate::function::FunctionContext;
use crate::llvm_sys::*;
use crate::module::ModuleContext;
use crate::types::TypesBuilder;
use llvm_sys::LLVMAtomicOrdering;
#[cfg(feature="llvm-10-or-greater")]
use llvm_sys::LLVMAtomicRMWBinOp;
use llvm_sys::LLVMOpcode;
use llvm_sys::LLVMTypeKind::LLVMVoidTypeKind;
#[cfg(feature="llvm-11-or-greater")]
use std::convert::TryInto;
impl Instruction {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
debug!("Processing instruction {:?}", unsafe {
print_to_string(inst)
});
match unsafe { LLVMGetInstructionOpcode(inst) } {
LLVMOpcode::LLVMAdd => Instruction::Add(Add::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMSub => Instruction::Sub(Sub::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMMul => Instruction::Mul(Mul::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMUDiv => Instruction::UDiv(UDiv::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMSDiv => Instruction::SDiv(SDiv::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMURem => Instruction::URem(URem::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMSRem => Instruction::SRem(SRem::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMAnd => Instruction::And(And::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMOr => Instruction::Or(Or::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMXor => Instruction::Xor(Xor::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMShl => Instruction::Shl(Shl::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMLShr => Instruction::LShr(LShr::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMAShr => Instruction::AShr(AShr::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFAdd => Instruction::FAdd(FAdd::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFSub => Instruction::FSub(FSub::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFMul => Instruction::FMul(FMul::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFDiv => Instruction::FDiv(FDiv::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFRem => Instruction::FRem(FRem::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFNeg => Instruction::FNeg(FNeg::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMExtractElement => {
Instruction::ExtractElement(ExtractElement::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMInsertElement => {
Instruction::InsertElement(InsertElement::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMShuffleVector => {
Instruction::ShuffleVector(ShuffleVector::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMExtractValue => {
Instruction::ExtractValue(ExtractValue::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMInsertValue => {
Instruction::InsertValue(InsertValue::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMAlloca => {
Instruction::Alloca(Alloca::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMLoad => Instruction::Load(Load::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMStore => Instruction::Store(Store::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFence => Instruction::Fence(Fence::from_llvm_ref(inst)),
LLVMOpcode::LLVMAtomicCmpXchg => {
Instruction::CmpXchg(CmpXchg::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMAtomicRMW => {
Instruction::AtomicRMW(AtomicRMW::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMGetElementPtr => {
Instruction::GetElementPtr(GetElementPtr::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMTrunc => Instruction::Trunc(Trunc::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMZExt => Instruction::ZExt(ZExt::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMSExt => Instruction::SExt(SExt::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFPTrunc => {
Instruction::FPTrunc(FPTrunc::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMFPExt => Instruction::FPExt(FPExt::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFPToUI => {
Instruction::FPToUI(FPToUI::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMFPToSI => {
Instruction::FPToSI(FPToSI::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMUIToFP => {
Instruction::UIToFP(UIToFP::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMSIToFP => {
Instruction::SIToFP(SIToFP::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMPtrToInt => {
Instruction::PtrToInt(PtrToInt::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMIntToPtr => {
Instruction::IntToPtr(IntToPtr::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMBitCast => {
Instruction::BitCast(BitCast::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMAddrSpaceCast => {
Instruction::AddrSpaceCast(AddrSpaceCast::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMICmp => Instruction::ICmp(ICmp::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMFCmp => Instruction::FCmp(FCmp::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMPHI => Instruction::Phi(Phi::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMSelect => {
Instruction::Select(Select::from_llvm_ref(inst, ctx, func_ctx))
},
#[cfg(feature="llvm-10-or-greater")]
LLVMOpcode::LLVMFreeze => {
Instruction::Freeze(Freeze::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMCall => Instruction::Call(Call::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMVAArg => Instruction::VAArg(VAArg::from_llvm_ref(inst, ctx, func_ctx)),
LLVMOpcode::LLVMLandingPad => {
Instruction::LandingPad(LandingPad::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMCatchPad => {
Instruction::CatchPad(CatchPad::from_llvm_ref(inst, ctx, func_ctx))
},
LLVMOpcode::LLVMCleanupPad => {
Instruction::CleanupPad(CleanupPad::from_llvm_ref(inst, ctx, func_ctx))
},
opcode => panic!(
"Instruction::from_llvm_ref called with a terminator instruction (opcode {:?})",
opcode
),
}
}
}
macro_rules! unop_from_llvm {
($inst:ident) => {
impl $inst {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
operand: Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, 0) },
ctx,
func_ctx,
),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
};
}
macro_rules! binop_from_llvm {
($inst:ident) => {
impl $inst {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
operand0: Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, 0) },
ctx,
func_ctx,
),
operand1: Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, 1) },
ctx,
func_ctx,
),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
};
}
binop_from_llvm!(Add);
binop_from_llvm!(Sub);
binop_from_llvm!(Mul);
binop_from_llvm!(UDiv);
binop_from_llvm!(SDiv);
binop_from_llvm!(URem);
binop_from_llvm!(SRem);
binop_from_llvm!(And);
binop_from_llvm!(Or);
binop_from_llvm!(Xor);
binop_from_llvm!(Shl);
binop_from_llvm!(LShr);
binop_from_llvm!(AShr);
binop_from_llvm!(FAdd);
binop_from_llvm!(FSub);
binop_from_llvm!(FMul);
binop_from_llvm!(FDiv);
binop_from_llvm!(FRem);
unop_from_llvm!(FNeg);
#[cfg(feature="llvm-10-or-greater")]
unop_from_llvm!(Freeze);
impl ExtractElement {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
vector: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
index: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl InsertElement {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
Self {
vector: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
element: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
index: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl ShuffleVector {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
#[cfg(feature="llvm-10-or-lower")]
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
#[cfg(feature="llvm-11-or-greater")]
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
#[cfg(feature="llvm-10-or-lower")]
mask: Constant::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx),
#[cfg(feature="llvm-11-or-greater")]
mask: {
let ret_ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) });
match ret_ty.as_ref() {
Type::VectorType { num_elements, scalable, .. } => {
assert_eq!(*num_elements as u32, unsafe { LLVMGetNumMaskElements(inst) });
let undef_elem = unsafe { LLVMGetUndefMaskElem() };
ConstantRef::new(Constant::Vector(
(0 .. *num_elements)
.map(|i| unsafe { LLVMGetMaskValue(inst, i.try_into().unwrap()) })
.map(|val| if val == undef_elem {
Constant::Undef(ctx.types.i32())
} else {
if *scalable {
assert!(val == 0, "LLVM 11+ only allows zero or undef for mask elements in a ShuffleVector on scalable vectors");
} else {
assert!(val >= 0);
}
let val: u32 = val.try_into().unwrap();
Constant::Int { value: val.into(), bits: 32 }
})
.map(ConstantRef::new)
.collect()
))
},
ty => panic!("ShuffleVector: expected instruction result type to be a vector type; got {:?}", ty),
}
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl ExtractValue {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
aggregate: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
indices: unsafe {
let num_indices = LLVMGetNumIndices(inst);
let ptr = LLVMGetIndices(inst);
std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl InsertValue {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
aggregate: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
element: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
indices: unsafe {
let num_indices = LLVMGetNumIndices(inst);
let ptr = LLVMGetIndices(inst);
std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Alloca {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
allocated_type: ctx
.types
.type_from_llvm_ref(unsafe { LLVMGetAllocatedType(inst) }),
num_elements: Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, 0) },
ctx,
func_ctx,
),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
alignment: unsafe { LLVMGetAlignment(inst) },
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Load {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
volatile: unsafe { LLVMGetVolatile(inst) } != 0,
atomicity: {
let ordering = unsafe { LLVMGetOrdering(inst) };
if ordering == LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic {
None
} else {
Some(Atomicity {
synch_scope: SynchronizationScope::from_llvm_ref(inst),
mem_ordering: MemoryOrdering::from_llvm(ordering),
})
}
},
alignment: unsafe { LLVMGetAlignment(inst) },
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Store {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
volatile: unsafe { LLVMGetVolatile(inst) } != 0,
atomicity: {
let ordering = unsafe { LLVMGetOrdering(inst) };
if ordering == LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic {
None
} else {
Some(Atomicity {
synch_scope: SynchronizationScope::from_llvm_ref(inst),
mem_ordering: MemoryOrdering::from_llvm(ordering),
})
}
},
alignment: unsafe { LLVMGetAlignment(inst) },
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Fence {
pub(crate) fn from_llvm_ref(inst: LLVMValueRef) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 0);
Self {
atomicity: Atomicity {
synch_scope: SynchronizationScope::from_llvm_ref(inst),
mem_ordering: MemoryOrdering::from_llvm(unsafe { LLVMGetOrdering(inst) }),
},
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl CmpXchg {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
Self {
address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
expected: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
replacement: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
volatile: unsafe { LLVMGetVolatile(inst) } != 0,
atomicity: Atomicity {
synch_scope: SynchronizationScope::from_llvm_ref(inst),
mem_ordering: MemoryOrdering::from_llvm(unsafe {
LLVMGetCmpXchgSuccessOrdering(inst)
}),
},
failure_memory_ordering: MemoryOrdering::from_llvm(unsafe {
LLVMGetCmpXchgFailureOrdering(inst)
}),
#[cfg(feature="llvm-10-or-greater")]
weak: unsafe { LLVMGetWeak(inst) } != 0,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl AtomicRMW {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
#[cfg(feature="llvm-10-or-greater")]
operation: RMWBinOp::from_llvm(unsafe { LLVMGetAtomicRMWBinOp(inst) }),
address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
volatile: unsafe { LLVMGetVolatile(inst) } != 0,
atomicity: Atomicity {
synch_scope: SynchronizationScope::from_llvm_ref(inst),
mem_ordering: MemoryOrdering::from_llvm(unsafe { LLVMGetOrdering(inst) }),
},
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl GetElementPtr {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
address: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
indices: {
let num_indices = unsafe { LLVMGetNumIndices(inst) };
(1 ..= num_indices)
.map(|i| {
Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, i) }, ctx, func_ctx)
})
.collect()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
in_bounds: unsafe { LLVMIsInBounds(inst) } != 0,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
macro_rules! typed_unop_from_llvm {
($inst:ident) => {
impl $inst {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
operand: Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, 0) },
ctx,
func_ctx,
),
to_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
};
}
typed_unop_from_llvm!(Trunc);
typed_unop_from_llvm!(ZExt);
typed_unop_from_llvm!(SExt);
typed_unop_from_llvm!(FPTrunc);
typed_unop_from_llvm!(FPExt);
typed_unop_from_llvm!(FPToUI);
typed_unop_from_llvm!(FPToSI);
typed_unop_from_llvm!(UIToFP);
typed_unop_from_llvm!(SIToFP);
typed_unop_from_llvm!(PtrToInt);
typed_unop_from_llvm!(IntToPtr);
typed_unop_from_llvm!(BitCast);
typed_unop_from_llvm!(AddrSpaceCast);
impl ICmp {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
predicate: IntPredicate::from_llvm(unsafe { LLVMGetICmpPredicate(inst) }),
operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl FCmp {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 2);
Self {
predicate: FPPredicate::from_llvm(unsafe { LLVMGetFCmpPredicate(inst) }),
operand0: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
operand1: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Phi {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
incoming_values: {
let num_incoming = unsafe { LLVMCountIncoming(inst) };
(0 .. num_incoming)
.map(|i| {
let operand = Operand::from_llvm_ref(
unsafe { LLVMGetIncomingValue(inst, i) },
ctx,
func_ctx,
);
let name = func_ctx
.bb_names
.get(unsafe { &LLVMGetIncomingBlock(inst, i) })
.expect("Failed to find incoming block in the map")
.clone();
(operand, name)
})
.collect()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
to_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl Select {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 3);
Self {
condition: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
true_value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 1) }, ctx, func_ctx),
false_value: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 2) }, ctx, func_ctx),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
pub(crate) struct CallInfo {
pub function: Either<InlineAssembly, Operand>,
pub arguments: Vec<(Operand, Vec<ParameterAttribute>)>,
pub return_attributes: Vec<ParameterAttribute>,
pub function_attributes: Vec<FunctionAttribute>,
pub calling_convention: CallingConvention,
}
impl CallInfo {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
use llvm_sys::{LLVMAttributeFunctionIndex, LLVMAttributeReturnIndex};
Self {
function: {
let called_val = unsafe { LLVMGetCalledValue(inst) };
let asm = unsafe { LLVMIsAInlineAsm(called_val) };
if !asm.is_null() {
Either::Left(InlineAssembly::from_llvm_ref(asm, &mut ctx.types))
} else {
Either::Right(Operand::from_llvm_ref(called_val, ctx, func_ctx))
}
},
arguments: {
let num_args: u32 = unsafe { LLVMGetNumArgOperands(inst) } as u32;
(0 .. num_args)
.map(|i| {
let operand = Operand::from_llvm_ref(
unsafe { LLVMGetOperand(inst, i) },
ctx,
func_ctx,
);
let attrs = {
let num_attrs =
unsafe { LLVMGetCallSiteAttributeCount(inst, (i + 1) as u32) };
let mut attrs: Vec<LLVMAttributeRef> =
Vec::with_capacity(num_attrs as usize);
unsafe {
LLVMGetCallSiteAttributes(inst, (i + 1) as u32, attrs.as_mut_ptr());
attrs.set_len(num_attrs as usize);
};
attrs
.into_iter()
.map(|attr| ParameterAttribute::from_llvm_ref(attr, &ctx.attrsdata))
.collect()
};
(operand, attrs)
})
.collect()
},
return_attributes: {
let num_attrs =
unsafe { LLVMGetCallSiteAttributeCount(inst, LLVMAttributeReturnIndex) };
let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
unsafe {
LLVMGetCallSiteAttributes(inst, LLVMAttributeReturnIndex, attrs.as_mut_ptr());
attrs.set_len(num_attrs as usize);
};
attrs
.into_iter()
.map(|attr| ParameterAttribute::from_llvm_ref(attr, &ctx.attrsdata))
.collect()
},
function_attributes: {
let num_attrs =
unsafe { LLVMGetCallSiteAttributeCount(inst, LLVMAttributeFunctionIndex) };
let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
unsafe {
LLVMGetCallSiteAttributes(inst, LLVMAttributeFunctionIndex, attrs.as_mut_ptr());
attrs.set_len(num_attrs as usize);
};
attrs
.into_iter()
.map(|attr| FunctionAttribute::from_llvm_ref(attr, &ctx.attrsdata))
.collect()
},
calling_convention: CallingConvention::from_u32(unsafe {
LLVMGetInstructionCallConv(inst)
}),
}
}
}
impl Call {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
let callinfo = CallInfo::from_llvm_ref(inst, ctx, func_ctx);
Self {
function: callinfo.function,
arguments: callinfo.arguments,
return_attributes: callinfo.return_attributes,
dest: if unsafe {
LLVMGetTypeKind(LLVMGetReturnType(LLVMGetCalledFunctionType(inst)))
== LLVMVoidTypeKind
} {
None
} else {
Some(Name::name_or_num(
unsafe { get_value_name(inst) },
&mut func_ctx.ctr,
))
},
function_attributes: callinfo.function_attributes,
is_tail_call: unsafe { LLVMIsTailCall(inst) } != 0,
calling_convention: callinfo.calling_convention,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl VAArg {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
assert_eq!(unsafe { LLVMGetNumOperands(inst) }, 1);
Self {
arg_list: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
cur_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl LandingPad {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
result_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(inst) }),
clauses: {
let num_clauses = unsafe { LLVMGetNumClauses(inst) };
(0 .. num_clauses)
.map(|i| LandingPadClause::from_llvm_ref(unsafe { LLVMGetClause(inst, i) }))
.collect()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
cleanup: unsafe { LLVMIsCleanup(inst) } != 0,
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl CatchPad {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
catch_switch: Operand::from_llvm_ref(
unsafe { LLVMGetParentCatchSwitch(inst) },
ctx,
func_ctx,
),
args: {
let num_args = unsafe { LLVMGetNumArgOperands(inst) };
(0 .. num_args)
.map(|i| {
Operand::from_llvm_ref(unsafe { LLVMGetArgOperand(inst, i) }, ctx, func_ctx)
})
.collect()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl CleanupPad {
pub(crate) fn from_llvm_ref(
inst: LLVMValueRef,
ctx: &mut ModuleContext,
func_ctx: &mut FunctionContext,
) -> Self {
Self {
parent_pad: Operand::from_llvm_ref(unsafe { LLVMGetOperand(inst, 0) }, ctx, func_ctx),
args: {
let num_args = unsafe { LLVMGetNumArgOperands(inst) };
(0 .. num_args)
.map(|i| {
Operand::from_llvm_ref(unsafe { LLVMGetArgOperand(inst, i) }, ctx, func_ctx)
})
.collect()
},
dest: Name::name_or_num(unsafe { get_value_name(inst) }, &mut func_ctx.ctr),
#[cfg(feature="llvm-9-or-greater")]
debugloc: DebugLoc::from_llvm_with_col(inst),
}
}
}
impl SynchronizationScope {
pub(crate) fn from_llvm_ref(inst: LLVMValueRef) -> Self {
if unsafe { LLVMIsAtomicSingleThread(inst) } != 0 {
SynchronizationScope::SingleThread
} else {
SynchronizationScope::System
}
}
}
impl MemoryOrdering {
#[rustfmt::skip]
pub(crate) fn from_llvm(ao: LLVMAtomicOrdering) -> Self {
match ao {
LLVMAtomicOrdering::LLVMAtomicOrderingUnordered => MemoryOrdering::Unordered,
LLVMAtomicOrdering::LLVMAtomicOrderingMonotonic => MemoryOrdering::Monotonic,
LLVMAtomicOrdering::LLVMAtomicOrderingAcquire => MemoryOrdering::Acquire,
LLVMAtomicOrdering::LLVMAtomicOrderingRelease => MemoryOrdering::Release,
LLVMAtomicOrdering::LLVMAtomicOrderingAcquireRelease => MemoryOrdering::AcquireRelease,
LLVMAtomicOrdering::LLVMAtomicOrderingSequentiallyConsistent => MemoryOrdering::SequentiallyConsistent,
LLVMAtomicOrdering::LLVMAtomicOrderingNotAtomic => MemoryOrdering::NotAtomic,
}
}
}
#[cfg(feature="llvm-10-or-greater")]
impl RMWBinOp {
pub(crate) fn from_llvm(rmwbo: LLVMAtomicRMWBinOp) -> Self {
match rmwbo {
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXchg => Self::Xchg,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd => Self::Add,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub => Self::Sub,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAnd => Self::And,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpNand => Self::Nand,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpOr => Self::Or,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpXor => Self::Xor,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMax => Self::Max,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpMin => Self::Min,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMax => Self::UMax,
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpUMin => Self::UMin,
#[cfg(feature="llvm-10-or-greater")]
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFAdd => Self::FAdd,
#[cfg(feature="llvm-10-or-greater")]
LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpFSub => Self::FSub,
}
}
}
impl InlineAssembly {
pub(crate) fn from_llvm_ref(asm: LLVMValueRef, types: &mut TypesBuilder) -> Self {
Self {
ty: types.type_from_llvm_ref(unsafe { LLVMTypeOf(asm) }),
}
}
}
impl LandingPadClause {
pub(crate) fn from_llvm_ref(_lpc: LLVMValueRef) -> Self {
Self {}
}
}