1use crate::instruction::Instruction;
2use crate::name::Name;
3use crate::terminator::Terminator;
4
5#[derive(PartialEq, Clone, Debug, Hash)]
9pub struct BasicBlock {
10 pub name: Name,
11 pub instrs: Vec<Instruction>,
12 pub term: Terminator,
13}
14
15impl BasicBlock {
16 pub fn new(name: Name) -> Self {
18 use crate::terminator::Unreachable;
19 Self {
20 name,
21 instrs: vec![],
22 term: Terminator::Unreachable(Unreachable {
23 debugloc: None,
24 }),
25 }
26 }
27}
28
29use crate::from_llvm::*;
34use crate::function::FunctionContext;
35use crate::llvm_sys::*;
36use crate::module::ModuleContext;
37use llvm_sys::LLVMOpcode;
38use llvm_sys::LLVMTypeKind::LLVMVoidTypeKind;
39
40impl BasicBlock {
41 pub(crate) fn from_llvm_ref(
42 bb: LLVMBasicBlockRef,
43 ctx: &mut ModuleContext,
44 func_ctx: &mut FunctionContext,
45 ) -> Self {
46 let name = Name::name_or_num(unsafe { get_bb_name(bb) }, &mut func_ctx.ctr);
47 debug_assert_eq!(
48 &name,
49 func_ctx
50 .bb_names
51 .get(&bb)
52 .expect("Expected to find bb in func_ctx.bb_names"),
53 );
54 debug!("Processing a basic block named {:?}", name);
55 Self {
56 name,
57 instrs: all_but_last(get_instructions(bb))
58 .map(|i| Instruction::from_llvm_ref(i, ctx, func_ctx))
59 .collect(),
60 term: Terminator::from_llvm_ref(
61 unsafe { LLVMGetBasicBlockTerminator(bb) },
62 ctx,
63 func_ctx,
64 ),
65 }
66 }
67
68 pub(crate) fn first_pass_names(
70 bb: LLVMBasicBlockRef,
71 ctr: &mut usize,
72 ) -> (Name, Vec<(LLVMValueRef, Name)>) {
73 let bbname = Name::name_or_num(unsafe { get_bb_name(bb) }, ctr);
74 let mut instnames = vec![];
75 for inst in all_but_last(get_instructions(bb)).filter(|&i| needs_name(i)) {
76 instnames.push((
77 inst,
78 Name::name_or_num(unsafe { get_value_name(inst) }, ctr),
79 ));
80 }
81 let term = unsafe { LLVMGetBasicBlockTerminator(bb) };
82 if term_needs_name(term) {
83 instnames.push((
84 term,
85 Name::name_or_num(unsafe { get_value_name(term) }, ctr),
86 ));
87 }
88 (bbname, instnames)
89 }
90}
91
92fn needs_name(inst: LLVMValueRef) -> bool {
94 if unsafe { !get_value_name(inst).is_empty() } {
95 return true; }
97 match unsafe { LLVMGetInstructionOpcode(inst) } {
98 LLVMOpcode::LLVMStore => false,
99 LLVMOpcode::LLVMFence => false,
100 LLVMOpcode::LLVMCall => {
101 let kind =
103 unsafe { LLVMGetTypeKind(LLVMGetReturnType(LLVMGetCalledFunctionType(inst))) };
104 kind != LLVMVoidTypeKind
105 },
106 _ => true, }
108}
109
110fn term_needs_name(term: LLVMValueRef) -> bool {
112 if unsafe { !get_value_name(term).is_empty() } {
113 return true; }
115 match unsafe { LLVMGetInstructionOpcode(term) } {
116 LLVMOpcode::LLVMInvoke => true,
117 LLVMOpcode::LLVMCatchSwitch => true,
118 LLVMOpcode::LLVMCallBr => true,
119 _ => false, }
121}