Skip to main content

llvm_ir/
module.rs

1//! Module: top-level container for globals, functions, and metadata.
2
3use crate::context::{FunctionId, GlobalId, TypeId};
4use crate::function::Function;
5use crate::value::GlobalVariable;
6use std::collections::HashMap;
7
8/// Public API for `DebugLocation`.
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub struct DebugLocation {
11    /// Public API for `line`.
12    pub line: u32,
13    /// Public API for `column`.
14    pub column: u32,
15}
16
17/// Top-level IR module.
18pub struct Module {
19    /// Public API for `name`.
20    pub name: String,
21    /// Public API for `source_filename`.
22    pub source_filename: Option<String>,
23    /// Public API for `target_triple`.
24    pub target_triple: Option<String>,
25    /// Public API for `data_layout`.
26    pub data_layout: Option<String>,
27    /// Public API for `globals`.
28    pub globals: Vec<GlobalVariable>,
29    /// Public API for `functions`.
30    pub functions: Vec<Function>,
31    /// Public API for `function_names`.
32    pub function_names: HashMap<String, FunctionId>,
33    /// Public API for `global_names`.
34    pub global_names: HashMap<String, GlobalId>,
35    /// Named type definitions in declaration order (for printing).
36    pub named_types: Vec<(String, TypeId)>,
37    /// `!N = !DILocation(...)` records keyed by metadata id `N`.
38    pub debug_locations: HashMap<u32, DebugLocation>,
39    /// Raw metadata node definitions keyed by numeric id, e.g. `!12 = !DIFile(...)`.
40    pub metadata_nodes: HashMap<u32, String>,
41    /// Named metadata definitions in insertion order, e.g. `!llvm.dbg.cu = !{!0}`.
42    pub named_metadata: Vec<(String, String)>,
43}
44
45impl Module {
46    /// Public API for `new`.
47    pub fn new(name: impl Into<String>) -> Self {
48        Module {
49            name: name.into(),
50            source_filename: None,
51            target_triple: None,
52            data_layout: None,
53            globals: Vec::new(),
54            functions: Vec::new(),
55            function_names: HashMap::new(),
56            global_names: HashMap::new(),
57            named_types: Vec::new(),
58            debug_locations: HashMap::new(),
59            metadata_nodes: HashMap::new(),
60            named_metadata: Vec::new(),
61        }
62    }
63
64    // -----------------------------------------------------------------------
65    // Functions
66    // -----------------------------------------------------------------------
67
68    /// Public API for `add_function`.
69    pub fn add_function(&mut self, f: Function) -> FunctionId {
70        let id = FunctionId(self.functions.len() as u32);
71        self.function_names.insert(f.name.clone(), id);
72        self.functions.push(f);
73        id
74    }
75
76    /// Public API for `function`.
77    pub fn function(&self, id: FunctionId) -> &Function {
78        &self.functions[id.0 as usize]
79    }
80
81    /// Public API for `function_mut`.
82    pub fn function_mut(&mut self, id: FunctionId) -> &mut Function {
83        &mut self.functions[id.0 as usize]
84    }
85
86    /// Public API for `get_function`.
87    pub fn get_function(&self, name: &str) -> Option<(FunctionId, &Function)> {
88        self.function_names
89            .get(name)
90            .map(|&id| (id, &self.functions[id.0 as usize]))
91    }
92
93    /// Public API for `get_function_id`.
94    pub fn get_function_id(&self, name: &str) -> Option<FunctionId> {
95        self.function_names.get(name).copied()
96    }
97
98    /// Public API for `num_functions`.
99    pub fn num_functions(&self) -> usize {
100        self.functions.len()
101    }
102
103    // -----------------------------------------------------------------------
104    // Globals
105    // -----------------------------------------------------------------------
106
107    /// Public API for `add_global`.
108    pub fn add_global(&mut self, gv: GlobalVariable) -> GlobalId {
109        let id = GlobalId(self.globals.len() as u32);
110        self.global_names.insert(gv.name.clone(), id);
111        self.globals.push(gv);
112        id
113    }
114
115    /// Public API for `global`.
116    pub fn global(&self, id: GlobalId) -> &GlobalVariable {
117        &self.globals[id.0 as usize]
118    }
119
120    /// Public API for `global_mut`.
121    pub fn global_mut(&mut self, id: GlobalId) -> &mut GlobalVariable {
122        &mut self.globals[id.0 as usize]
123    }
124
125    /// Public API for `get_global`.
126    pub fn get_global(&self, name: &str) -> Option<(GlobalId, &GlobalVariable)> {
127        self.global_names
128            .get(name)
129            .map(|&id| (id, &self.globals[id.0 as usize]))
130    }
131
132    /// Public API for `get_global_id`.
133    pub fn get_global_id(&self, name: &str) -> Option<GlobalId> {
134        self.global_names.get(name).copied()
135    }
136
137    /// Public API for `num_globals`.
138    pub fn num_globals(&self) -> usize {
139        self.globals.len()
140    }
141
142    // -----------------------------------------------------------------------
143    // Named types
144    // -----------------------------------------------------------------------
145
146    /// Register a named struct type for emission in the module header.
147    /// Duplicate names are silently ignored.
148    pub fn register_named_type(&mut self, name: impl Into<String>, ty: TypeId) {
149        let name = name.into();
150        if !self.named_types.iter().any(|(n, _)| n == &name) {
151            self.named_types.push((name, ty));
152        }
153    }
154
155    /// Public API for `set_debug_location`.
156    pub fn set_debug_location(&mut self, id: u32, loc: DebugLocation) {
157        self.debug_locations.insert(id, loc);
158    }
159
160    /// Public API for `debug_location`.
161    pub fn debug_location(&self, id: u32) -> Option<DebugLocation> {
162        self.debug_locations.get(&id).copied()
163    }
164
165    /// Public API for `set_metadata_node`.
166    pub fn set_metadata_node(&mut self, id: u32, value: impl Into<String>) {
167        self.metadata_nodes.insert(id, value.into());
168    }
169
170    /// Public API for `metadata_node`.
171    pub fn metadata_node(&self, id: u32) -> Option<&str> {
172        self.metadata_nodes.get(&id).map(String::as_str)
173    }
174
175    /// Public API for `set_named_metadata`.
176    pub fn set_named_metadata(&mut self, name: impl Into<String>, value: impl Into<String>) {
177        let name = name.into();
178        let value = value.into();
179        if let Some((_, v)) = self.named_metadata.iter_mut().find(|(n, _)| *n == name) {
180            *v = value;
181        } else {
182            self.named_metadata.push((name, value));
183        }
184    }
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190    use crate::context::Context;
191    use crate::value::{GlobalVariable, Linkage};
192
193    #[test]
194    fn module_functions() {
195        let mut ctx = Context::new();
196        let fn_ty = ctx.mk_fn_type(ctx.i32_ty, vec![], false);
197        let f = Function::new("foo", fn_ty, vec![], Linkage::External);
198        let mut m = Module::new("test");
199        let id = m.add_function(f);
200        assert_eq!(id, FunctionId(0));
201        assert_eq!(m.function(id).name, "foo");
202        assert_eq!(m.get_function_id("foo"), Some(FunctionId(0)));
203    }
204
205    #[test]
206    fn module_globals() {
207        let ctx = Context::new();
208        let gv = GlobalVariable {
209            name: "x".to_string(),
210            ty: ctx.i32_ty,
211            initializer: None,
212            is_constant: false,
213            linkage: Linkage::External,
214        };
215        let mut m = Module::new("test");
216        let id = m.add_global(gv);
217        assert_eq!(id, GlobalId(0));
218        assert_eq!(m.global(id).name, "x");
219    }
220}