llvm_ir/
basicblock.rs

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
121
use crate::instruction::Instruction;
use crate::name::Name;
use crate::terminator::Terminator;

/// A `BasicBlock` is a sequence of zero or more non-terminator instructions
/// followed by a single terminator instruction which ends the block.
/// Basic blocks are discussed in the [LLVM 14 docs on Functions](https://releases.llvm.org/14.0.0/docs/LangRef.html#functionstructure)
#[derive(PartialEq, Clone, Debug)]
pub struct BasicBlock {
    pub name: Name,
    pub instrs: Vec<Instruction>,
    pub term: Terminator,
}

impl BasicBlock {
    /// A `BasicBlock` instance with no instructions and an `Unreachable` terminator
    pub fn new(name: Name) -> Self {
        use crate::terminator::Unreachable;
        Self {
            name,
            instrs: vec![],
            term: Terminator::Unreachable(Unreachable {
                debugloc: None,
            }),
        }
    }
}

// ********* //
// from_llvm //
// ********* //

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,
            ),
        }
    }

    // Returns the name of the basic block and a vec of (instruction/terminator, name) pairs
    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)
    }
}

// Given only the LLVMValueRef for an Instruction, determine whether it needs a name
fn needs_name(inst: LLVMValueRef) -> bool {
    if unsafe { !get_value_name(inst).is_empty() } {
        return true; // has a string name
    }
    match unsafe { LLVMGetInstructionOpcode(inst) } {
        LLVMOpcode::LLVMStore => false,
        LLVMOpcode::LLVMFence => false,
        LLVMOpcode::LLVMCall => {
            // needs a name unless we're calling a void function
            let kind =
                unsafe { LLVMGetTypeKind(LLVMGetReturnType(LLVMGetCalledFunctionType(inst))) };
            kind != LLVMVoidTypeKind
        },
        _ => true, // all other instructions have results (destinations) and thus will need names
    }
}

// Given only the LLVMValueRef for a Terminator, determine whether it needs a name
fn term_needs_name(term: LLVMValueRef) -> bool {
    if unsafe { !get_value_name(term).is_empty() } {
        return true; // has a string name
    }
    match unsafe { LLVMGetInstructionOpcode(term) } {
        LLVMOpcode::LLVMInvoke => true,
        LLVMOpcode::LLVMCatchSwitch => true,
        LLVMOpcode::LLVMCallBr => true,
        _ => false, // all other terminators have no result (destination) and thus don't need names
    }
}