llvm_ir/
basicblock.rs

1use crate::instruction::Instruction;
2use crate::name::Name;
3use crate::terminator::Terminator;
4
5/// A `BasicBlock` is a sequence of zero or more non-terminator instructions
6/// followed by a single terminator instruction which ends the block.
7/// Basic blocks are discussed in the [LLVM 14 docs on Functions](https://releases.llvm.org/14.0.0/docs/LangRef.html#functionstructure)
8#[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    /// A `BasicBlock` instance with no instructions and an `Unreachable` terminator
17    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
29// ********* //
30// from_llvm //
31// ********* //
32
33use 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    // Returns the name of the basic block and a vec of (instruction/terminator, name) pairs
69    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
92// Given only the LLVMValueRef for an Instruction, determine whether it needs a name
93fn needs_name(inst: LLVMValueRef) -> bool {
94    if unsafe { !get_value_name(inst).is_empty() } {
95        return true; // has a string name
96    }
97    match unsafe { LLVMGetInstructionOpcode(inst) } {
98        LLVMOpcode::LLVMStore => false,
99        LLVMOpcode::LLVMFence => false,
100        LLVMOpcode::LLVMCall => {
101            // needs a name unless we're calling a void function
102            let kind =
103                unsafe { LLVMGetTypeKind(LLVMGetReturnType(LLVMGetCalledFunctionType(inst))) };
104            kind != LLVMVoidTypeKind
105        },
106        _ => true, // all other instructions have results (destinations) and thus will need names
107    }
108}
109
110// Given only the LLVMValueRef for a Terminator, determine whether it needs a name
111fn term_needs_name(term: LLVMValueRef) -> bool {
112    if unsafe { !get_value_name(term).is_empty() } {
113        return true; // has a string name
114    }
115    match unsafe { LLVMGetInstructionOpcode(term) } {
116        LLVMOpcode::LLVMInvoke => true,
117        LLVMOpcode::LLVMCatchSwitch => true,
118        LLVMOpcode::LLVMCallBr => true,
119        _ => false, // all other terminators have no result (destination) and thus don't need names
120    }
121}