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