llir/values/instruction/
switch.rs1use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMValueAsBasicBlock};
2use llvm_sys::prelude::LLVMValueRef;
3use std::marker::PhantomData;
4
5use crate::values::*;
6use crate::*;
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub struct SwitchCase<'ctx> {
11 pub case: IntConstant<'ctx>,
14 pub destination: Block<'ctx>,
16}
17
18#[derive(Copy, Clone, PartialEq, Eq, Hash)]
20pub struct SwitchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>);
21
22impl_instr_debug!(SwitchInstruction);
23
24impl_as_operand_for_instr!(SwitchInstruction);
25
26impl_send_sync!(SwitchInstruction);
27
28impl<'ctx> GetDebugMetadata<'ctx> for SwitchInstruction<'ctx> {}
29
30impl<'ctx> InstructionDebugLoc for SwitchInstruction<'ctx> {}
31
32impl<'ctx> InstructionTrait<'ctx> for SwitchInstruction<'ctx> {}
33
34impl<'ctx> SwitchInstruction<'ctx> {
35 pub fn condition(&self) -> Operand<'ctx> {
37 Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) })
38 }
39
40 pub fn default_destination(&self) -> Block<'ctx> {
43 let operand = unsafe { LLVMGetOperand(self.0, 1) };
44 let block = unsafe { LLVMValueAsBasicBlock(operand) };
45 Block::from_llvm(block)
46 }
47
48 pub fn num_cases(&self) -> usize {
50 let num_operands = unsafe { LLVMGetNumOperands(self.0) as usize };
51 (num_operands - 2) / 2
52 }
53
54 pub fn cases(&self) -> Vec<SwitchCase<'ctx>> {
56 (0..self.num_cases() as u32)
57 .map(|i| SwitchCase {
58 case: IntConstant::from_llvm(unsafe { LLVMGetOperand(self.0, i * 2 + 2) }),
59 destination: Block::from_llvm(unsafe { LLVMValueAsBasicBlock(LLVMGetOperand(self.0, i * 2 + 3)) }),
60 })
61 .collect()
62 }
63
64 pub fn destinations(&self) -> Vec<Block<'ctx>> {
66 vec![
67 vec![self.default_destination()],
68 self.cases().into_iter().map(|case| case.destination).collect(),
69 ]
70 .concat()
71 }
72}
73
74impl<'ctx> ValueOpcode for SwitchInstruction<'ctx> {
75 fn opcode(&self) -> Opcode {
76 Opcode::Switch
77 }
78}
79
80impl<'ctx> AsInstruction<'ctx> for SwitchInstruction<'ctx> {
81 fn as_instruction(&self) -> Instruction<'ctx> {
82 Instruction::Switch(*self)
83 }
84}
85
86impl_positional_value_ref!(SwitchInstruction, 0);
87
88impl_positional_from_llvm_value!(SwitchInstruction);