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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
pub mod basic_block;
pub mod builder;
pub mod data;
pub mod instruction;
pub mod layout;
pub mod param_attrs;
pub mod parser;
pub mod print;

pub use parser::parse;

use super::{
    module::{
        attributes::Attribute, linkage::Linkage, name::Name,
        preemption_specifier::PreemptionSpecifier, unnamed_addr::UnnamedAddr,
        visibility::Visibility,
    },
    types::{Type, Types},
    value::ConstantData,
};
use crate::traits::basic_block::{BasicBlockData, BasicBlockLayout};
use basic_block::BasicBlock;
use id_arena::Id;
use instruction::InstructionId;
use param_attrs::ParameterAttribute;
use std::fmt;

pub type FunctionId = Id<Function>;

pub type PersonalityFunc = (Type, ConstantData);

pub struct Function {
    pub name: String,
    pub is_var_arg: bool,
    pub result_ty: Type,
    pub params: Vec<Parameter>,
    pub linkage: Linkage,
    pub preemption_specifier: PreemptionSpecifier,
    pub visibility: Visibility,
    pub unnamed_addr: Option<UnnamedAddr>,
    pub func_attrs: Vec<Attribute>,
    pub ret_attrs: Vec<param_attrs::ParameterAttribute>,
    pub personality: Option<PersonalityFunc>,
    pub data: data::Data,
    pub layout: layout::Layout,
    pub types: Types,
    // pub is_prototype: bool,
}

#[derive(Debug, Clone)]
pub struct Parameter {
    pub name: Name,
    pub ty: Type,
    pub attrs: Vec<ParameterAttribute>,
}

impl Function {
    pub fn new<T: AsRef<str>>(
        name: T,
        result_ty: Type,
        params: Vec<Parameter>,
        is_var_arg: bool,
        types: Types,
    ) -> Self {
        Self {
            name: name.as_ref().to_string(),
            is_var_arg,
            result_ty,
            params,
            linkage: Linkage::Common,
            preemption_specifier: PreemptionSpecifier::DsoLocal,
            visibility: Visibility::Default,
            unnamed_addr: None,
            func_attrs: vec![],
            ret_attrs: vec![],
            personality: None,
            data: data::Data::default(),
            layout: layout::Layout::default(),
            types,
        }
    }

    pub fn name(&self) -> &String {
        &self.name
    }

    pub fn params(&self) -> &[Parameter] {
        &self.params
    }

    pub fn is_var_arg(&self) -> bool {
        self.is_var_arg
    }

    pub fn is_prototype(&self) -> bool {
        self.layout.is_empty()
    }

    pub fn remove_inst(&mut self, inst: InstructionId) -> Option<()> {
        self.data.remove_uses(inst);
        self.layout.remove_inst(inst)
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        print::FunctionAsmPrinter::new(f).print(self)
    }
}

impl Parameter {
    pub fn new(ty: Type) -> Self {
        Self {
            name: Name::Number(0),
            ty,
            attrs: vec![],
        }
    }

    pub fn to_string(&self, types: &Types) -> String {
        format!("{} %{:?}", types.to_string(self.ty), self.name)
    }
}

impl BasicBlockData<BasicBlock> for Function {
    fn get(&self, id: Id<BasicBlock>) -> &BasicBlock {
        &self.data.basic_blocks[id]
    }
}

impl BasicBlockLayout<BasicBlock> for Function {
    fn order(&self) -> Box<dyn Iterator<Item = Id<BasicBlock>> + '_> {
        Box::new(self.layout.block_iter())
    }
}