Skip to main content

llir/values/instruction/
switch.rs

1use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMValueAsBasicBlock};
2use llvm_sys::prelude::LLVMValueRef;
3use std::marker::PhantomData;
4
5use crate::values::*;
6use crate::*;
7
8/// One Case of switch
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub struct SwitchCase<'ctx> {
11  /// The value that the switch operand will be checked against.
12  /// This value is always integer constant.
13  pub case: IntConstant<'ctx>,
14  /// The block it will take when the value matches
15  pub destination: Block<'ctx>,
16}
17
18/// [Switch instruction](https://llvm.org/docs/LangRef.html#switch-instruction)
19#[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  /// Get the value that is checked against
36  pub fn condition(&self) -> Operand<'ctx> {
37    Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) })
38  }
39
40  /// Get the default block, which is the block this instruction will jump to when
41  /// no branch target is matching the value
42  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  /// Get the number of cases
49  pub fn num_cases(&self) -> usize {
50    let num_operands = unsafe { LLVMGetNumOperands(self.0) as usize };
51    (num_operands - 2) / 2
52  }
53
54  /// Get the cases
55  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  /// Get destination blocks
65  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);