llir/values/
block.rs

1use llvm_sys::core::*;
2use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
3use std::marker::PhantomData;
4
5use crate::values::*;
6use crate::*;
7
8/// A block inside of function
9#[derive(Copy, Clone, PartialEq, Eq, Hash)]
10pub struct Block<'ctx>(LLVMBasicBlockRef, PhantomData<&'ctx ()>);
11
12impl<'ctx> std::fmt::Debug for Block<'ctx> {
13  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
14    f.debug_tuple("Block").field(&self.0).finish()
15  }
16}
17
18impl_send_sync!(Block);
19
20impl<'ctx> GetDebugMetadata<'ctx> for Block<'ctx> {}
21
22impl<'ctx> Block<'ctx> {
23  /// Get the function containing this block
24  pub fn parent_function(&self) -> Function<'ctx> {
25    let func_ptr = unsafe { LLVMGetBasicBlockParent(self.0) };
26    Function::from_llvm(func_ptr)
27  }
28
29  /// Iterate the instructions inside this block
30  ///
31  /// ```
32  /// for instr in blk.iter_instructions() {
33  ///   // Do things to instr...
34  /// }
35  /// ```
36  pub fn iter_instructions(&self) -> BlockInstructionIterator<'ctx> {
37    let first_instr = unsafe { LLVMGetFirstInstruction(self.0) };
38    if first_instr.is_null() {
39      BlockInstructionIterator {
40        curr_instr: None,
41        marker: PhantomData,
42      }
43    } else {
44      BlockInstructionIterator {
45        curr_instr: Some(first_instr),
46        marker: PhantomData,
47      }
48    }
49  }
50
51  /// Get the first instruction inside this block
52  pub fn first_instruction(&self) -> Option<Instruction<'ctx>> {
53    let first_instr = unsafe { LLVMGetFirstInstruction(self.0) };
54    if first_instr.is_null() {
55      None
56    } else {
57      Some(Instruction::from_llvm(first_instr))
58    }
59  }
60
61  /// Get the last instruction inside this block
62  pub fn last_instruction(&self) -> Option<Instruction<'ctx>> {
63    let last_instr = unsafe { LLVMGetLastInstruction(self.0) };
64    if last_instr.is_null() {
65      None
66    } else {
67      Some(Instruction::from_llvm(last_instr))
68    }
69  }
70
71  /// Get the name of the block
72  pub fn name(&self) -> String {
73    unsafe { utils::raw_to_string(LLVMGetBasicBlockName(self.0)) }
74  }
75
76  /// Get the destination blocks that can be reached
77  pub fn destination_blocks(&self) -> Vec<Block<'ctx>> {
78    if let Some(term) = self.last_instruction() {
79      match term {
80        Instruction::Branch(br) => br.destinations(),
81        Instruction::Switch(sw) => sw.destinations(),
82        _ => vec![],
83      }
84    } else {
85      vec![]
86    }
87  }
88
89  /// Checking if a block is a loop entry block
90  ///
91  /// Will iterate through all blocks inside the function and see if there is an
92  /// loop based unconditional branch going to this block. This function is relying
93  /// on the debug symbol `llvm.loop`
94  pub fn is_loop_entry_block(&self) -> bool {
95    for blk in self.parent_function().iter_blocks() {
96      match blk.last_instruction() {
97        Some(Instruction::Branch(BranchInstruction::Unconditional(un))) => {
98          if let Some(is_loop_jump) = un.is_loop_jump() {
99            if is_loop_jump && un.destination() == *self {
100              return true;
101            }
102          }
103        }
104        _ => {}
105      }
106    }
107    return false;
108  }
109}
110
111impl<'ctx> BlockRef for Block<'ctx> {
112  fn block_ref(&self) -> LLVMBasicBlockRef {
113    self.0
114  }
115}
116
117impl<'ctx> ValueRef for Block<'ctx> {
118  fn value_ref(&self) -> LLVMValueRef {
119    unsafe { LLVMBasicBlockAsValue(self.0) }
120  }
121}
122
123impl<'ctx> FromLLVMBlock for Block<'ctx> {
124  fn from_llvm(ptr: LLVMBasicBlockRef) -> Self {
125    Block(ptr, PhantomData)
126  }
127}
128
129#[doc(hidden)]
130pub struct BlockInstructionIterator<'ctx> {
131  curr_instr: Option<LLVMValueRef>,
132  marker: PhantomData<&'ctx ()>,
133}
134
135impl<'ctx> Iterator for BlockInstructionIterator<'ctx> {
136  type Item = Instruction<'ctx>;
137
138  fn next(&mut self) -> Option<Self::Item> {
139    match self.curr_instr {
140      Some(curr_instr_ptr) => {
141        let result = Some(Instruction::from_llvm(curr_instr_ptr));
142        let next_ptr = unsafe { LLVMGetNextInstruction(curr_instr_ptr) };
143        if next_ptr.is_null() {
144          self.curr_instr = None;
145        } else {
146          self.curr_instr = Some(next_ptr);
147        }
148        result
149      }
150      None => None,
151    }
152  }
153}