melior/
execution_engine.rs1use crate::{ir::Module, logical_result::LogicalResult, string_ref::StringRef, Error};
2use mlir_sys::{
3 mlirExecutionEngineCreate, mlirExecutionEngineDestroy, mlirExecutionEngineDumpToObjectFile,
4 mlirExecutionEngineInvokePacked, mlirExecutionEngineLookup, mlirExecutionEngineRegisterSymbol,
5 MlirExecutionEngine,
6};
7
8pub struct ExecutionEngine {
10 raw: MlirExecutionEngine,
11}
12
13impl ExecutionEngine {
14 pub fn new(
16 module: &Module,
17 optimization_level: usize,
18 shared_library_paths: &[&str],
19 enable_object_dump: bool,
20 ) -> Self {
21 Self {
22 raw: unsafe {
23 mlirExecutionEngineCreate(
24 module.to_raw(),
25 optimization_level as i32,
26 shared_library_paths.len() as i32,
27 shared_library_paths
28 .iter()
29 .map(|&string| StringRef::new(string).to_raw())
30 .collect::<Vec<_>>()
31 .as_ptr(),
32 enable_object_dump,
33 )
34 },
35 }
36 }
37
38 pub fn lookup(&self, name: &str) -> *mut () {
40 unsafe { mlirExecutionEngineLookup(self.raw, StringRef::new(name).to_raw()) as *mut () }
41 }
42
43 pub unsafe fn invoke_packed(&self, name: &str, arguments: &mut [*mut ()]) -> Result<(), Error> {
52 let result = LogicalResult::from_raw(mlirExecutionEngineInvokePacked(
53 self.raw,
54 StringRef::new(name).to_raw(),
55 arguments.as_mut_ptr() as _,
56 ));
57
58 if result.is_success() {
59 Ok(())
60 } else {
61 Err(Error::InvokeFunction)
62 }
63 }
64
65 pub unsafe fn register_symbol(&self, name: &str, ptr: *mut ()) {
73 mlirExecutionEngineRegisterSymbol(self.raw, StringRef::new(name).to_raw(), ptr as _);
74 }
75
76 pub fn dump_to_object_file(&self, path: &str) {
78 unsafe { mlirExecutionEngineDumpToObjectFile(self.raw, StringRef::new(path).to_raw()) }
79 }
80}
81
82impl Drop for ExecutionEngine {
83 fn drop(&mut self) {
84 unsafe { mlirExecutionEngineDestroy(self.raw) }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::{pass, test::create_test_context};
92
93 #[test]
94 fn invoke_packed() {
95 let context = create_test_context();
96
97 let mut module = Module::parse(
98 &context,
99 r#"
100 module {
101 func.func @add(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface } {
102 %res = arith.addi %arg0, %arg0 : i32
103 return %res : i32
104 }
105 }
106 "#,
107 )
108 .unwrap();
109
110 let pass_manager = pass::PassManager::new(&context);
111 pass_manager.add_pass(pass::conversion::create_func_to_llvm());
112
113 pass_manager
114 .nested_under("func.func")
115 .add_pass(pass::conversion::create_arith_to_llvm());
116
117 assert_eq!(pass_manager.run(&mut module), Ok(()));
118
119 let engine = ExecutionEngine::new(&module, 2, &[], false);
120
121 let mut argument = 42;
122 let mut result = -1;
123
124 assert_eq!(
125 unsafe {
126 engine.invoke_packed(
127 "add",
128 &mut [
129 &mut argument as *mut i32 as *mut (),
130 &mut result as *mut i32 as *mut (),
131 ],
132 )
133 },
134 Ok(())
135 );
136
137 assert_eq!(argument, 42);
138 assert_eq!(result, 84);
139 }
140
141 #[test]
142 fn dump_to_object_file() {
143 let context = create_test_context();
144
145 let mut module = Module::parse(
146 &context,
147 r#"
148 module {
149 func.func @add(%arg0 : i32) -> i32 {
150 %res = arith.addi %arg0, %arg0 : i32
151 return %res : i32
152 }
153 }
154 "#,
155 )
156 .unwrap();
157
158 let pass_manager = pass::PassManager::new(&context);
159 pass_manager.add_pass(pass::conversion::create_func_to_llvm());
160
161 pass_manager
162 .nested_under("func.func")
163 .add_pass(pass::conversion::create_arith_to_llvm());
164
165 assert_eq!(pass_manager.run(&mut module), Ok(()));
166
167 ExecutionEngine::new(&module, 2, &[], true).dump_to_object_file("/tmp/melior/test.o");
168 }
169}