use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMValueAsBasicBlock};
use llvm_sys::prelude::LLVMValueRef;
use std::marker::PhantomData;
use crate::values::*;
use crate::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SwitchCase<'ctx> {
pub case: IntConstant<'ctx>,
pub destination: Block<'ctx>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct SwitchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>);
impl_instr_debug!(SwitchInstruction);
impl_as_operand_for_instr!(SwitchInstruction);
impl_send_sync!(SwitchInstruction);
impl<'ctx> GetDebugMetadata<'ctx> for SwitchInstruction<'ctx> {}
impl<'ctx> InstructionDebugLoc for SwitchInstruction<'ctx> {}
impl<'ctx> InstructionTrait<'ctx> for SwitchInstruction<'ctx> {}
impl<'ctx> SwitchInstruction<'ctx> {
pub fn condition(&self) -> Operand<'ctx> {
Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) })
}
pub fn default_destination(&self) -> Block<'ctx> {
let operand = unsafe { LLVMGetOperand(self.0, 1) };
let block = unsafe { LLVMValueAsBasicBlock(operand) };
Block::from_llvm(block)
}
pub fn num_cases(&self) -> usize {
let num_operands = unsafe { LLVMGetNumOperands(self.0) as usize };
(num_operands - 2) / 2
}
pub fn cases(&self) -> Vec<SwitchCase<'ctx>> {
(0..self.num_cases() as u32)
.map(|i| SwitchCase {
case: IntConstant::from_llvm(unsafe { LLVMGetOperand(self.0, i * 2 + 2) }),
destination: Block::from_llvm(unsafe { LLVMValueAsBasicBlock(LLVMGetOperand(self.0, i * 2 + 3)) }),
})
.collect()
}
pub fn destinations(&self) -> Vec<Block<'ctx>> {
vec![
vec![self.default_destination()],
self.cases().into_iter().map(|case| case.destination).collect(),
]
.concat()
}
}
impl<'ctx> ValueOpcode for SwitchInstruction<'ctx> {
fn opcode(&self) -> Opcode {
Opcode::Switch
}
}
impl<'ctx> AsInstruction<'ctx> for SwitchInstruction<'ctx> {
fn as_instruction(&self) -> Instruction<'ctx> {
Instruction::Switch(*self)
}
}
impl_positional_value_ref!(SwitchInstruction, 0);
impl_positional_from_llvm_value!(SwitchInstruction);