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;

/// 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 12 docs on Functions](https://releases.llvm.org/12.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 {
                #[cfg(feature="llvm-9-or-greater")]
                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) != "" } {
        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) != "" } {
        return true; // has a string name
    }
    match unsafe { LLVMGetInstructionOpcode(term) } {
        LLVMOpcode::LLVMInvoke => true,
        LLVMOpcode::LLVMCatchSwitch => true,
        #[cfg(feature="llvm-9-or-greater")]
        LLVMOpcode::LLVMCallBr => true,
        _ => false, // all other terminators have no result (destination) and thus don't need names
    }
}