use crate::types::Type;
use crate::value::{valref, SubclassKind, Value, ValueRef};
pub use crate::opcode::FCmpPred;
pub use crate::opcode::ICmpPred;
pub use crate::opcode::Opcode;
fn make_inst(opcode: Opcode, ty: Type, operands: Vec<ValueRef>) -> ValueRef {
let mut v = Value::new(ty).with_subclass(SubclassKind::Instruction);
v.opcode = Some(opcode); v.operands = operands; v.num_operands = v.operands.len();
valref(v)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperandKind {
Any,
Integer,
Float,
Pointer,
Vector,
Label,
BasicBlock,
Function,
Metadata,
SameAsResult,
SameAsOp0,
SameAsOp1,
Int1,
Int8,
Int16,
Int32,
Int64,
}
#[derive(Debug, Clone)]
pub struct InstructionInfo {
pub opcode: Opcode,
pub name: &'static str,
pub num_operands: u8,
pub is_terminator: bool,
pub is_binary_op: bool,
pub is_bitwise_op: bool,
pub is_cast: bool,
pub is_memory_op: bool,
pub has_side_effects: bool,
pub is_commutative: bool,
pub may_read_memory: bool,
pub may_write_memory: bool,
pub operand_types: &'static [OperandKind],
}
fn build_info_table() -> [InstructionInfo; 65] {
use Opcode::*;
use OperandKind as OK;
[
InstructionInfo {
opcode: Opcode::Ret,
name: "invalid",
num_operands: 0,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[],
},
InstructionInfo {
opcode: Ret,
name: "ret",
num_operands: 1,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: Br,
name: "br",
num_operands: 3,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Int1, OK::Label, OK::Label],
},
InstructionInfo {
opcode: Switch,
name: "switch",
num_operands: 3,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer, OK::Label, OK::Label],
},
InstructionInfo {
opcode: IndirectBr,
name: "indirectbr",
num_operands: 2,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Pointer, OK::Label],
},
InstructionInfo {
opcode: Invoke,
name: "invoke",
num_operands: 4,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: true,
may_write_memory: true,
operand_types: &[OK::Function, OK::Label, OK::Label, OK::Any],
},
InstructionInfo {
opcode: CallBr,
name: "callbr",
num_operands: 4,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: true,
may_write_memory: true,
operand_types: &[OK::Function, OK::Label, OK::Label, OK::Any],
},
InstructionInfo {
opcode: Resume,
name: "resume",
num_operands: 1,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: CatchSwitch,
name: "catchswitch",
num_operands: 2,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any, OK::Label],
},
InstructionInfo {
opcode: CatchRet,
name: "catchret",
num_operands: 2,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any, OK::Label],
},
InstructionInfo {
opcode: CleanupRet,
name: "cleanupret",
num_operands: 1,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: Unreachable,
name: "unreachable",
num_operands: 0,
is_terminator: true,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[],
},
InstructionInfo {
opcode: Add,
name: "add",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: FAdd,
name: "fadd",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Sub,
name: "sub",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: FSub,
name: "fsub",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Mul,
name: "mul",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: FMul,
name: "fmul",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: UDiv,
name: "udiv",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: SDiv,
name: "sdiv",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: FDiv,
name: "fdiv",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: URem,
name: "urem",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: SRem,
name: "srem",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: FRem,
name: "frem",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Shl,
name: "shl",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: LShr,
name: "lshr",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: AShr,
name: "ashr",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: And,
name: "and",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: true,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Or,
name: "or",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: true,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Xor,
name: "xor",
num_operands: 2,
is_terminator: false,
is_binary_op: true,
is_bitwise_op: true,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: true,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Alloca,
name: "alloca",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: true,
operand_types: &[OK::Int64],
},
InstructionInfo {
opcode: Load,
name: "load",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: false,
is_commutative: false,
may_read_memory: true,
may_write_memory: false,
operand_types: &[OK::Pointer],
},
InstructionInfo {
opcode: Store,
name: "store",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: true,
operand_types: &[OK::Any, OK::Pointer],
},
InstructionInfo {
opcode: GetElementPtr,
name: "getelementptr",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Pointer, OK::Integer],
},
InstructionInfo {
opcode: Fence,
name: "fence",
num_operands: 0,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: true,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[],
},
InstructionInfo {
opcode: CmpXchg,
name: "cmpxchg",
num_operands: 3,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: true,
is_commutative: false,
may_read_memory: true,
may_write_memory: true,
operand_types: &[OK::Pointer, OK::SameAsOp1, OK::SameAsOp1],
},
InstructionInfo {
opcode: AtomicRMW,
name: "atomicrmw",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: true,
is_commutative: false,
may_read_memory: true,
may_write_memory: true,
operand_types: &[OK::Pointer, OK::SameAsResult],
},
InstructionInfo {
opcode: Trunc,
name: "trunc",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: ZExt,
name: "zext",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: SExt,
name: "sext",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: FPTrunc,
name: "fptrunc",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Float],
},
InstructionInfo {
opcode: FPExt,
name: "fpext",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Float],
},
InstructionInfo {
opcode: FPToUI,
name: "fptoui",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Float],
},
InstructionInfo {
opcode: FPToSI,
name: "fptosi",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Float],
},
InstructionInfo {
opcode: UIToFP,
name: "uitofp",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: SIToFP,
name: "sitofp",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: PtrToInt,
name: "ptrtoint",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Pointer],
},
InstructionInfo {
opcode: IntToPtr,
name: "inttoptr",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer],
},
InstructionInfo {
opcode: BitCast,
name: "bitcast",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: AddrSpaceCast,
name: "addrspacecast",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: true,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Pointer],
},
InstructionInfo {
opcode: ICmp,
name: "icmp",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Integer, OK::Integer],
},
InstructionInfo {
opcode: FCmp,
name: "fcmp",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Float, OK::Float],
},
InstructionInfo {
opcode: Call,
name: "call",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: true,
is_commutative: false,
may_read_memory: true,
may_write_memory: true,
operand_types: &[OK::Function, OK::Any],
},
InstructionInfo {
opcode: Phi,
name: "phi",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult, OK::Label],
},
InstructionInfo {
opcode: Select,
name: "select",
num_operands: 3,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Int1, OK::SameAsResult, OK::SameAsResult],
},
InstructionInfo {
opcode: Freeze,
name: "freeze",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::SameAsResult],
},
InstructionInfo {
opcode: VAArg,
name: "va_arg",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: true,
has_side_effects: false,
is_commutative: false,
may_read_memory: true,
may_write_memory: false,
operand_types: &[OK::Pointer],
},
InstructionInfo {
opcode: ExtractElement,
name: "extractelement",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Vector, OK::Integer],
},
InstructionInfo {
opcode: InsertElement,
name: "insertelement",
num_operands: 3,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Vector, OK::Any, OK::Integer],
},
InstructionInfo {
opcode: ShuffleVector,
name: "shufflevector",
num_operands: 3,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Vector, OK::Vector, OK::Vector],
},
InstructionInfo {
opcode: ExtractValue,
name: "extractvalue",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: InsertValue,
name: "insertvalue",
num_operands: 2,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any, OK::SameAsResult],
},
InstructionInfo {
opcode: LandingPad,
name: "landingpad",
num_operands: 0,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[],
},
InstructionInfo {
opcode: CatchPad,
name: "catchpad",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
InstructionInfo {
opcode: CleanupPad,
name: "cleanuppad",
num_operands: 1,
is_terminator: false,
is_binary_op: false,
is_bitwise_op: false,
is_cast: false,
is_memory_op: false,
has_side_effects: false,
is_commutative: false,
may_read_memory: false,
may_write_memory: false,
operand_types: &[OK::Any],
},
]
}
fn info_table() -> &'static [InstructionInfo; 65] {
use std::sync::OnceLock;
static TABLE: OnceLock<[InstructionInfo; 65]> = OnceLock::new();
TABLE.get_or_init(build_info_table)
}
pub fn get_instruction_info(opcode: Opcode) -> &'static InstructionInfo {
&info_table()[opcode.as_u32() as usize]
}
pub fn get_opcode_name(opcode: Opcode) -> &'static str {
opcode.as_mnemonic()
}
pub fn is_terminator(opcode: Opcode) -> bool {
opcode.is_terminator()
}
pub fn is_binary_op(opcode: Opcode) -> bool {
opcode.is_binary_op()
}
pub fn is_cast(opcode: Opcode) -> bool {
opcode.is_cast()
}
pub fn is_memory_access(opcode: Opcode) -> bool {
opcode.is_memory_op()
}
pub fn may_read_memory(opcode: Opcode) -> bool {
get_instruction_info(opcode).may_read_memory
}
pub fn may_write_memory(opcode: Opcode) -> bool {
get_instruction_info(opcode).may_write_memory
}
pub fn has_side_effects(opcode: Opcode) -> bool {
get_instruction_info(opcode).has_side_effects
}
pub fn is_commutative(opcode: Opcode) -> bool {
get_instruction_info(opcode).is_commutative
}
pub fn is_bitwise_op(opcode: Opcode) -> bool {
get_instruction_info(opcode).is_bitwise_op
}
pub fn get_operand_count(opcode: Opcode) -> u8 {
get_instruction_info(opcode).num_operands
}
pub fn get_result_type(opcode: Opcode, operands: &[Type]) -> Type {
match opcode {
Opcode::ICmp | Opcode::FCmp => Type::i1(),
Opcode::PtrToInt
| Opcode::IntToPtr
| Opcode::BitCast
| Opcode::AddrSpaceCast
| Opcode::Trunc
| Opcode::ZExt
| Opcode::SExt
| Opcode::FPTrunc
| Opcode::FPExt
| Opcode::FPToUI
| Opcode::FPToSI
| Opcode::UIToFP
| Opcode::SIToFP => {
Type::void()
}
Opcode::Load | Opcode::Alloca => {
if !operands.is_empty() {
operands[0].clone()
} else {
Type::void()
}
}
Opcode::GetElementPtr => Type::pointer(0),
Opcode::Select | Opcode::Phi | Opcode::Freeze => {
if !operands.is_empty() {
operands[0].clone()
} else {
Type::void()
}
}
_ => {
if !operands.is_empty() {
operands[0].clone()
} else {
Type::void()
}
}
}
}
pub fn ret_void() -> ValueRef {
make_inst(Opcode::Ret, Type::void(), vec![])
}
pub fn ret_val(val: ValueRef) -> ValueRef {
make_inst(Opcode::Ret, Type::void(), vec![val])
}
pub fn br(label: ValueRef) -> ValueRef {
make_inst(Opcode::Br, Type::void(), vec![label])
}
pub fn br_cond(cond: ValueRef, if_true: ValueRef, if_false: ValueRef) -> ValueRef {
make_inst(Opcode::Br, Type::void(), vec![cond, if_true, if_false])
}
pub fn switch(val: ValueRef, default: ValueRef, cases: Vec<(ValueRef, ValueRef)>) -> ValueRef {
let mut ops = vec![val, default];
for (v, l) in cases {
ops.push(v);
ops.push(l);
}
make_inst(Opcode::Switch, Type::void(), ops)
}
pub fn unreachable() -> ValueRef {
make_inst(Opcode::Unreachable, Type::void(), vec![])
}
pub fn create_invoke(
callee: ValueRef,
normal_dest: ValueRef,
unwind_dest: ValueRef,
args: Vec<ValueRef>,
return_ty: Type,
) -> ValueRef {
let mut ops = vec![callee, normal_dest, unwind_dest];
ops.extend(args);
make_inst(Opcode::Invoke, return_ty, ops)
}
pub fn create_resume(value: ValueRef) -> ValueRef {
make_inst(Opcode::Resume, Type::void(), vec![value])
}
pub fn create_landingpad(ty: Type, personality: ValueRef, _num_clauses: u32) -> ValueRef {
make_inst(Opcode::LandingPad, ty, vec![personality])
}
pub fn add(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Add, ty, vec![a, b])
}
pub fn sub(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Sub, ty, vec![a, b])
}
pub fn mul(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Mul, ty, vec![a, b])
}
pub fn udiv(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::UDiv, ty, vec![a, b])
}
pub fn sdiv(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::SDiv, ty, vec![a, b])
}
pub fn urem(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::URem, ty, vec![a, b])
}
pub fn srem(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::SRem, ty, vec![a, b])
}
pub fn fadd(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::FAdd, ty, vec![a, b])
}
pub fn fsub(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::FSub, ty, vec![a, b])
}
pub fn fmul(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::FMul, ty, vec![a, b])
}
pub fn fdiv(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::FDiv, ty, vec![a, b])
}
pub fn frem(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::FRem, ty, vec![a, b])
}
pub fn shl(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Shl, ty, vec![a, b])
}
pub fn lshr(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::LShr, ty, vec![a, b])
}
pub fn ashr(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::AShr, ty, vec![a, b])
}
pub fn and(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::And, ty, vec![a, b])
}
pub fn or(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Or, ty, vec![a, b])
}
pub fn xor(a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Xor, ty, vec![a, b])
}
pub fn alloca(alloc_ty: Type) -> ValueRef {
let byte_size = {
let s = alloc_ty.size_in_bytes();
if s == 0 {
8u64
} else {
s
}
};
let size_val = crate::constants::const_int(Type::i64(), byte_size as i64);
make_inst(Opcode::Alloca, Type::pointer(0), vec![size_val])
}
pub fn load(load_ty: Type, ptr: ValueRef) -> ValueRef {
make_inst(Opcode::Load, load_ty, vec![ptr])
}
pub fn store(val: ValueRef, ptr: ValueRef) -> ValueRef {
make_inst(Opcode::Store, Type::void(), vec![val, ptr])
}
pub fn getelementptr(_pointee_ty: Type, ptr: ValueRef, indices: Vec<ValueRef>) -> ValueRef {
let mut ops = vec![ptr];
ops.extend(indices);
let result_ty = Type::pointer(0);
make_inst(Opcode::GetElementPtr, result_ty, ops)
}
pub fn create_cmpxchg(
ptr: ValueRef,
cmp: ValueRef,
new_val: ValueRef,
_success_ordering: u32,
_failure_ordering: u32,
) -> ValueRef {
let ty = cmp.borrow().ty.clone();
make_inst(Opcode::CmpXchg, ty, vec![ptr, cmp, new_val])
}
pub fn create_atomicrmw(_op: u32, ptr: ValueRef, val: ValueRef, _ordering: u32) -> ValueRef {
let ty = val.borrow().ty.clone();
make_inst(Opcode::AtomicRMW, ty, vec![ptr, val])
}
pub fn create_fence(_ordering: u32) -> ValueRef {
make_inst(Opcode::Fence, Type::void(), vec![])
}
pub fn icmp(pred: ICmpPred, a: ValueRef, b: ValueRef) -> ValueRef {
let inst = make_inst(Opcode::ICmp, Type::i1(), vec![a, b]);
inst.borrow_mut().name = format!("icmp.{}", pred);
inst
}
pub fn fcmp(pred: crate::opcode::FCmpPred, a: ValueRef, b: ValueRef) -> ValueRef {
let inst = make_inst(Opcode::FCmp, Type::i1(), vec![a, b]);
inst.borrow_mut().name = format!("fcmp.{}", pred);
inst
}
pub fn call(return_ty: Type, func: ValueRef, args: Vec<ValueRef>) -> ValueRef {
let mut ops = vec![func];
ops.extend(args);
make_inst(Opcode::Call, return_ty, ops)
}
pub fn phi(ty: Type, incoming: Vec<(ValueRef, ValueRef)>) -> ValueRef {
let mut ops = Vec::new();
for (val, label) in incoming {
ops.push(val);
ops.push(label);
}
make_inst(Opcode::Phi, ty, ops)
}
pub fn select(cond: ValueRef, a: ValueRef, b: ValueRef) -> ValueRef {
let ty = a.borrow().ty.clone();
make_inst(Opcode::Select, ty, vec![cond, a, b])
}
pub fn trunc(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::Trunc, to_ty, vec![val])
}
pub fn zext(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::ZExt, to_ty, vec![val])
}
pub fn sext(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::SExt, to_ty, vec![val])
}
pub fn fptrunc(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::FPTrunc, to_ty, vec![val])
}
pub fn fpext(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::FPExt, to_ty, vec![val])
}
pub fn uitofp(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::UIToFP, to_ty, vec![val])
}
pub fn sitofp(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::SIToFP, to_ty, vec![val])
}
pub fn fptoui(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::FPToUI, to_ty, vec![val])
}
pub fn fptosi(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::FPToSI, to_ty, vec![val])
}
pub fn ptrtoint(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::PtrToInt, to_ty, vec![val])
}
pub fn inttoptr(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::IntToPtr, to_ty, vec![val])
}
pub fn bitcast(val: ValueRef, to_ty: Type) -> ValueRef {
make_inst(Opcode::BitCast, to_ty, vec![val])
}
pub fn create_extractvalue(agg: ValueRef, _indices: Vec<u32>, result_ty: Type) -> ValueRef {
make_inst(Opcode::ExtractValue, result_ty, vec![agg])
}
pub fn create_insertvalue(agg: ValueRef, val: ValueRef, _indices: Vec<u32>) -> ValueRef {
let ty = agg.borrow().ty.clone();
make_inst(Opcode::InsertValue, ty, vec![agg, val])
}
pub fn create_extractelement(vec: ValueRef, idx: ValueRef) -> ValueRef {
make_inst(Opcode::ExtractElement, Type::i32(), vec![vec, idx])
}
pub fn create_insertelement(vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
let ty = vec.borrow().ty.clone();
make_inst(Opcode::InsertElement, ty, vec![vec, elt, idx])
}
pub fn create_shufflevector(v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
let ty = v1.borrow().ty.clone();
make_inst(Opcode::ShuffleVector, ty, vec![v1, v2, mask])
}
pub fn create_freeze(val: ValueRef) -> ValueRef {
let ty = val.borrow().ty.clone();
make_inst(Opcode::Freeze, ty, vec![val])
}
pub fn create_vaarg(list: ValueRef, ty: Type) -> ValueRef {
make_inst(Opcode::VAArg, ty, vec![list])
}
pub fn is_used_by_terminator_only(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if inst_ref.uses.is_empty() {
return false;
}
for u in &inst_ref.uses {
if let Some(user) = u.user.upgrade() {
let user_ref = user.borrow();
if let Some(op) = user_ref.opcode {
if !op.is_terminator() {
return false;
}
} else {
return false;
}
}
}
true
}
pub fn is_safe_to_speculatively_execute(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if let Some(op) = inst_ref.opcode {
if op.is_binary_op() || op.is_cast() {
return true;
}
match op {
Opcode::GetElementPtr
| Opcode::ICmp
| Opcode::FCmp
| Opcode::Phi
| Opcode::Select
| Opcode::Freeze
| Opcode::ExtractElement
| Opcode::ExtractValue => true,
_ => false,
}
} else {
false
}
}
pub fn may_be_hoisted(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if let Some(op) = inst_ref.opcode {
if op.is_terminator() {
return false;
}
if may_write_memory(op) || has_side_effects(op) {
return false;
}
matches!(
op,
Opcode::Add
| Opcode::FAdd
| Opcode::Sub
| Opcode::FSub
| Opcode::Mul
| Opcode::FMul
| Opcode::UDiv
| Opcode::SDiv
| Opcode::FDiv
| Opcode::URem
| Opcode::SRem
| Opcode::FRem
| Opcode::Shl
| Opcode::LShr
| Opcode::AShr
| Opcode::And
| Opcode::Or
| Opcode::Xor
| Opcode::Trunc
| Opcode::ZExt
| Opcode::SExt
| Opcode::FPTrunc
| Opcode::FPExt
| Opcode::FPToUI
| Opcode::FPToSI
| Opcode::UIToFP
| Opcode::SIToFP
| Opcode::PtrToInt
| Opcode::IntToPtr
| Opcode::BitCast
| Opcode::AddrSpaceCast
| Opcode::ICmp
| Opcode::FCmp
| Opcode::GetElementPtr
| Opcode::Freeze
)
} else {
false
}
}
pub fn may_be_sunk(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if let Some(op) = inst_ref.opcode {
if op.is_terminator() || has_side_effects(op) {
return false;
}
if may_write_memory(op) {
return false;
}
true
} else {
false
}
}
pub fn is_idempotent(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if let Some(op) = inst_ref.opcode {
match op {
Opcode::Load => {
false
}
Opcode::Store | Opcode::Fence | Opcode::CmpXchg | Opcode::AtomicRMW => false,
Opcode::Call => false, _ if op.is_binary_op() || op.is_cast() => true,
Opcode::GetElementPtr
| Opcode::ICmp
| Opcode::FCmp
| Opcode::Select
| Opcode::Freeze
| Opcode::ExtractElement
| Opcode::ExtractValue => true,
_ => false,
}
} else {
false
}
}
pub fn drops_all_references(inst: &ValueRef) -> bool {
let inst_ref = inst.borrow();
if let Some(op) = inst_ref.opcode {
matches!(
op,
Opcode::Store | Opcode::Ret | Opcode::Br | Opcode::Switch
)
} else {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ret_void() {
let inst = ret_void();
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Ret));
assert_eq!(r.num_operands, 0);
}
#[test]
fn test_add_creates_correct_opcode() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = add(a, b);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Add));
assert_eq!(r.num_operands, 2);
}
#[test]
fn test_br_cond_creates_three_operands() {
let cond = crate::constants::const_bool(true);
let t = crate::basic_block::new_basic_block("true_bb");
let f = crate::basic_block::new_basic_block("false_bb");
let inst = br_cond(cond, t, f);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Br));
assert_eq!(r.num_operands, 3);
}
#[test]
fn test_call_creates_correct_opcode() {
let func = crate::function::new_function("target", Type::void(), &[]);
let inst = call(Type::void(), func, vec![]);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Call));
}
#[test]
fn test_icmp_predicate_stored() {
let a = crate::constants::const_i32(5);
let b = crate::constants::const_i32(3);
let inst = icmp(ICmpPred::Sgt, a, b);
let r = inst.borrow();
assert!(r.name.contains("icmp.sgt"));
}
#[test]
fn test_alloca_produces_pointer_type() {
let inst = alloca(Type::i32());
let r = inst.borrow();
assert!(matches!(r.ty.kind, crate::types::TypeKind::Pointer { .. }));
}
#[test]
fn test_phi_stores_incoming_pairs() {
let v1 = crate::constants::const_i32(1);
let bb1 = crate::basic_block::new_basic_block("entry");
let v2 = crate::constants::const_i32(2);
let bb2 = crate::basic_block::new_basic_block("loop");
let inst = phi(Type::i32(), vec![(v1, bb1), (v2, bb2)]);
let r = inst.borrow();
assert_eq!(r.num_operands, 4);
}
#[test]
fn test_get_instruction_info_ret() {
let info = get_instruction_info(Opcode::Ret);
assert_eq!(info.name, "ret");
assert!(info.is_terminator);
assert!(!info.is_binary_op);
assert!(info.has_side_effects);
}
#[test]
fn test_get_instruction_info_add() {
let info = get_instruction_info(Opcode::Add);
assert_eq!(info.name, "add");
assert!(info.is_binary_op);
assert!(info.is_commutative);
assert!(!info.is_terminator);
assert!(!info.has_side_effects);
}
#[test]
fn test_get_instruction_info_and_is_bitwise() {
let info = get_instruction_info(Opcode::And);
assert!(info.is_bitwise_op);
assert!(info.is_commutative);
}
#[test]
fn test_get_instruction_info_load_reads_memory() {
let info = get_instruction_info(Opcode::Load);
assert!(info.may_read_memory);
assert!(!info.may_write_memory);
assert!(info.is_memory_op);
}
#[test]
fn test_get_instruction_info_store_writes_memory() {
let info = get_instruction_info(Opcode::Store);
assert!(!info.may_read_memory);
assert!(info.may_write_memory);
}
#[test]
fn test_get_instruction_info_cmpxchg() {
let info = get_instruction_info(Opcode::CmpXchg);
assert!(info.may_read_memory);
assert!(info.may_write_memory);
assert!(info.has_side_effects);
}
#[test]
fn test_get_instruction_info_trunc_is_cast() {
let info = get_instruction_info(Opcode::Trunc);
assert!(info.is_cast);
assert!(!info.is_binary_op);
assert!(!info.is_terminator);
}
#[test]
fn test_get_instruction_info_all_casts() {
for op in [
Opcode::Trunc,
Opcode::ZExt,
Opcode::SExt,
Opcode::FPTrunc,
Opcode::FPExt,
Opcode::FPToUI,
Opcode::FPToSI,
Opcode::UIToFP,
Opcode::SIToFP,
Opcode::PtrToInt,
Opcode::IntToPtr,
Opcode::BitCast,
Opcode::AddrSpaceCast,
] {
let info = get_instruction_info(op);
assert!(info.is_cast, "Expected {} to be a cast", op);
}
}
#[test]
fn test_is_terminator() {
assert!(is_terminator(Opcode::Ret));
assert!(is_terminator(Opcode::Br));
assert!(is_terminator(Opcode::Switch));
assert!(!is_terminator(Opcode::Add));
assert!(!is_terminator(Opcode::Load));
}
#[test]
fn test_is_binary_op() {
assert!(is_binary_op(Opcode::Add));
assert!(is_binary_op(Opcode::FAdd));
assert!(is_binary_op(Opcode::Sub));
assert!(is_binary_op(Opcode::And));
assert!(is_binary_op(Opcode::Xor));
assert!(!is_binary_op(Opcode::Load));
assert!(!is_binary_op(Opcode::Call));
}
#[test]
fn test_is_cast() {
assert!(is_cast(Opcode::Trunc));
assert!(is_cast(Opcode::ZExt));
assert!(is_cast(Opcode::FPToUI));
assert!(is_cast(Opcode::BitCast));
assert!(!is_cast(Opcode::Add));
assert!(!is_cast(Opcode::Ret));
}
#[test]
fn test_is_memory_access() {
assert!(is_memory_access(Opcode::Alloca));
assert!(is_memory_access(Opcode::Load));
assert!(is_memory_access(Opcode::Store));
assert!(is_memory_access(Opcode::GetElementPtr));
assert!(!is_memory_access(Opcode::Add));
assert!(!is_memory_access(Opcode::Ret));
}
#[test]
fn test_may_read_write_memory() {
assert!(may_read_memory(Opcode::Load));
assert!(!may_read_memory(Opcode::Store));
assert!(!may_write_memory(Opcode::Load));
assert!(may_write_memory(Opcode::Store));
assert!(may_read_memory(Opcode::Call));
assert!(may_write_memory(Opcode::Call));
}
#[test]
fn test_has_side_effects() {
assert!(has_side_effects(Opcode::Ret));
assert!(has_side_effects(Opcode::Call));
assert!(has_side_effects(Opcode::Store));
assert!(!has_side_effects(Opcode::Add));
assert!(!has_side_effects(Opcode::Mul));
}
#[test]
fn test_is_commutative() {
assert!(is_commutative(Opcode::Add));
assert!(is_commutative(Opcode::FAdd));
assert!(is_commutative(Opcode::Mul));
assert!(is_commutative(Opcode::And));
assert!(is_commutative(Opcode::Or));
assert!(is_commutative(Opcode::Xor));
assert!(!is_commutative(Opcode::Sub));
assert!(!is_commutative(Opcode::FDiv));
}
#[test]
fn test_get_operand_count() {
assert_eq!(get_operand_count(Opcode::Ret), 1);
assert_eq!(get_operand_count(Opcode::Add), 2);
assert_eq!(get_operand_count(Opcode::Select), 3);
assert_eq!(get_operand_count(Opcode::Unreachable), 0);
}
#[test]
fn test_get_result_type_icmp_returns_i1() {
let result = get_result_type(Opcode::ICmp, &[]);
assert!(matches!(
result.kind,
crate::types::TypeKind::Integer { bits: 1 }
));
}
#[test]
fn test_create_invoke() {
let callee = crate::function::new_function("foo", Type::i32(), &[]);
let normal = crate::basic_block::new_basic_block("normal");
let unwind = crate::basic_block::new_basic_block("unwind");
let inst = create_invoke(callee.clone(), normal, unwind, vec![], Type::i32());
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Invoke));
assert_eq!(r.num_operands, 3); }
#[test]
fn test_create_resume() {
let val = crate::constants::const_i32(42);
let inst = create_resume(val);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Resume));
}
#[test]
fn test_create_landingpad() {
let personality = crate::function::new_function("__gxx_personality", Type::void(), &[]);
let inst = create_landingpad(Type::i32(), personality, 0);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::LandingPad));
}
#[test]
fn test_create_freeze() {
let val = crate::constants::const_i32(10);
let inst = create_freeze(val);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::Freeze));
}
#[test]
fn test_create_vaarg() {
let list = crate::constants::const_null_ptr(Type::i8());
let inst = create_vaarg(list, Type::i32());
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::VAArg));
}
#[test]
fn test_create_extractelement() {
let vec_v = crate::constants::const_int(Type::i32(), 0);
let idx = crate::constants::const_i32(0);
let inst = create_extractelement(vec_v, idx);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::ExtractElement));
}
#[test]
fn test_create_insertelement() {
let vec_v = crate::constants::const_int(Type::i32(), 0);
let elt = crate::constants::const_i32(5);
let idx = crate::constants::const_i32(0);
let inst = create_insertelement(vec_v, elt, idx);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::InsertElement));
}
#[test]
fn test_create_shufflevector() {
let v1 = crate::constants::const_int(Type::i32(), 0);
let v2 = crate::constants::const_int(Type::i32(), 0);
let mask = crate::constants::const_int(Type::i32(), 0);
let inst = create_shufflevector(v1, v2, mask);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::ShuffleVector));
}
#[test]
fn test_create_extractvalue() {
let agg = crate::constants::const_i32(0);
let inst = create_extractvalue(agg, vec![0], Type::i32());
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::ExtractValue));
}
#[test]
fn test_create_insertvalue() {
let agg = crate::constants::const_i32(10);
let val = crate::constants::const_i32(20);
let inst = create_insertvalue(agg, val, vec![0]);
let r = inst.borrow();
assert_eq!(r.opcode, Some(Opcode::InsertValue));
}
#[test]
fn test_is_safe_to_speculatively_execute_add() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = add(a, b);
assert!(is_safe_to_speculatively_execute(&inst));
}
#[test]
fn test_is_safe_to_speculatively_execute_load() {
let ptr = crate::constants::const_null_ptr(Type::i32());
let inst = load(Type::i32(), ptr);
assert!(!is_safe_to_speculatively_execute(&inst));
}
#[test]
fn test_may_be_hoisted_add() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = add(a, b);
assert!(may_be_hoisted(&inst));
}
#[test]
fn test_may_be_hoisted_store_fails() {
let val = crate::constants::const_i32(1);
let ptr = crate::constants::const_null_ptr(Type::i32());
let inst = store(val, ptr);
assert!(!may_be_hoisted(&inst));
}
#[test]
fn test_may_be_sunk_pure_op() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = add(a, b);
assert!(may_be_sunk(&inst));
}
#[test]
fn test_may_be_sunk_ret_fails() {
let inst = ret_void();
assert!(!may_be_sunk(&inst));
}
#[test]
fn test_is_idempotent() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = add(a, b);
assert!(is_idempotent(&inst));
}
#[test]
fn test_is_idempotent_store_fails() {
let val = crate::constants::const_i32(1);
let ptr = crate::constants::const_null_ptr(Type::i32());
let inst = store(val, ptr);
assert!(!is_idempotent(&inst));
}
#[test]
fn test_drops_all_references() {
let val = crate::constants::const_i32(1);
let ptr = crate::constants::const_null_ptr(Type::i32());
let inst = store(val, ptr);
assert!(drops_all_references(&inst));
}
#[test]
fn test_drops_all_references_br() {
let bb = crate::basic_block::new_basic_block("target");
let inst = br(bb);
assert!(drops_all_references(&inst));
}
#[test]
fn test_is_used_by_terminator_only_no_users() {
let a = crate::constants::const_i32(1);
let b = crate::constants::const_i32(2);
let inst = icmp(ICmpPred::Eq, a, b);
assert!(!is_used_by_terminator_only(&inst));
}
}