1use llvm_sys::core::*;
2use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
3use std::marker::PhantomData;
4
5use crate::values::*;
6use crate::*;
7
8#[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 pub fn parent_function(&self) -> Function<'ctx> {
25 let func_ptr = unsafe { LLVMGetBasicBlockParent(self.0) };
26 Function::from_llvm(func_ptr)
27 }
28
29 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 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 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 pub fn name(&self) -> String {
73 unsafe { utils::raw_to_string(LLVMGetBasicBlockName(self.0)) }
74 }
75
76 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 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}