pipeline_script/llvm/
context.rs1use crate::llvm::module::LLVMModule;
2use crate::llvm::types::LLVMType;
3use llvm_sys::core::{
4 LLVMArrayType2, LLVMConstStringInContext, LLVMContextCreate, LLVMContextDispose,
5 LLVMCreateMemoryBufferWithMemoryRangeCopy, LLVMFunctionType, LLVMInt32TypeInContext,
6 LLVMInt8TypeInContext, LLVMPointerTypeInContext, LLVMStructCreateNamed, LLVMStructSetBody,
7 LLVMVoidTypeInContext,
8};
9use llvm_sys::execution_engine::LLVMLinkInMCJIT;
10use llvm_sys::ir_reader::LLVMParseIRInContext;
11use llvm_sys::prelude::{LLVMContextRef, LLVMTypeRef, LLVMValueRef};
12use llvm_sys::target::{
13 LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget,
14};
15use std::ffi::{c_char, c_uint, CStr, CString};
16use std::ptr;
17
18#[derive(Clone, Debug)]
19pub struct LLVMContext {
20 llvm_ref: LLVMContextRef,
21}
22impl Default for LLVMContext {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl LLVMContext {
29 pub fn new() -> Self {
30 unsafe {
31 LLVM_InitializeNativeTarget();
32 LLVM_InitializeNativeAsmPrinter();
33 LLVM_InitializeNativeAsmParser();
34 LLVMLinkInMCJIT();
35 }
36 let ctx = unsafe { LLVMContextCreate() };
37 LLVMContext { llvm_ref: ctx }
38 }
39 pub fn with_mc_jit() -> Self {
40 unsafe {
41 LLVM_InitializeNativeTarget();
42 LLVM_InitializeNativeAsmPrinter();
43 LLVM_InitializeNativeAsmParser();
44 LLVMLinkInMCJIT();
45 }
46 let ctx = unsafe { LLVMContextCreate() };
47 LLVMContext { llvm_ref: ctx }
48 }
49 pub fn as_ref(&self) -> LLVMContextRef {
50 self.llvm_ref
51 }
52 pub fn parse_ir(&self, llvm_ir: impl AsRef<str>) -> core::result::Result<LLVMModule, String> {
53 let llvm_ir = llvm_ir.as_ref();
54 let input_data = llvm_ir.as_bytes();
55 let input_data_length = input_data.len();
56 let buffer_name = CString::new("llvm_ir_buffer").expect("CString::new failed");
58 let memory_buffer = unsafe {
59 LLVMCreateMemoryBufferWithMemoryRangeCopy(
60 input_data.as_ptr() as *const c_char,
61 input_data_length,
62 buffer_name.as_ptr(),
63 )
64 };
65 let mut module = ptr::null_mut();
67 let error_msg = &mut ptr::null_mut();
68
69 let result = unsafe {
70 LLVMParseIRInContext(
71 self.llvm_ref,
72 memory_buffer,
73 &mut module as *mut _,
74 error_msg,
75 )
76 };
77 if result == 0 {
78 return Ok(LLVMModule::from_raw(module));
79 }
80 let s = if !(*error_msg).is_null() {
81 let error_string = unsafe { CStr::from_ptr(*error_msg) };
83
84 error_string.to_string_lossy().into_owned()
86 } else {
87 String::new()
88 };
89 Err(s)
90 }
91 pub fn create_module(&self, name: impl AsRef<str>) -> LLVMModule {
92 LLVMModule::new(name)
93 }
94 pub fn i32_type(&self) -> LLVMType {
95 let t = unsafe { LLVMInt32TypeInContext(self.llvm_ref) };
96 LLVMType::Int32(t)
97 }
98 pub fn array_type(&self, el_ty: LLVMType, n: u64) -> LLVMType {
99 let t = unsafe { LLVMArrayType2(el_ty.as_llvm_type_ref(), n) };
100 LLVMType::Array(Box::new(el_ty), t)
101 }
102 pub fn i8_type(&self) -> LLVMType {
103 let t = unsafe { LLVMInt8TypeInContext(self.llvm_ref) };
104 LLVMType::Int8(t)
105 }
106 pub fn function_type(
107 &self,
108 return_type: LLVMType,
109 param_types: Vec<(String, LLVMType)>,
110 ) -> LLVMType {
111 let mut param_types0 = param_types
112 .iter()
113 .map(|t| t.1.as_llvm_type_ref())
114 .collect::<Vec<LLVMTypeRef>>();
115 let t = unsafe {
116 LLVMFunctionType(
117 return_type.as_llvm_type_ref(),
118 param_types0.as_mut_ptr(),
119 param_types.len() as c_uint,
120 0,
121 )
122 };
123 LLVMType::Function(Box::new(return_type), param_types, t)
124 }
125 pub fn function_type_with_var_arg(
126 &self,
127 return_type: LLVMType,
128 param_types: Vec<(String, LLVMType)>,
129 ) -> LLVMType {
130 let mut param_types0 = param_types
131 .iter()
132 .map(|t| t.1.as_llvm_type_ref())
133 .collect::<Vec<LLVMTypeRef>>();
134 let t = unsafe {
135 LLVMFunctionType(
136 return_type.as_llvm_type_ref(),
137 param_types0.as_mut_ptr(),
138 param_types.len() as c_uint,
139 1,
140 )
141 };
142 LLVMType::Function(Box::new(return_type), param_types, t)
143 }
144 pub fn unit_type(&self) -> LLVMType {
145 let t = unsafe { LLVMVoidTypeInContext(self.llvm_ref) };
146 LLVMType::Unit(t)
147 }
148 pub fn ptr_type(&self, t: LLVMType) -> LLVMType {
149 let t0 = unsafe { LLVMPointerTypeInContext(self.llvm_ref, 0) };
150 LLVMType::Pointer(Box::new(t), t0)
151 }
152 pub fn const_string(&self, str: impl AsRef<str>) -> LLVMValueRef {
153 let str0 = str.as_ref();
154 let str = CString::new(str0).unwrap();
155 unsafe { LLVMConstStringInContext(self.llvm_ref, str.as_ptr(), str0.len() as c_uint, 0) }
156 }
157 pub fn create_named_struct_type(
158 &self,
159 name: impl AsRef<str>,
160 element_type: Vec<(String, LLVMType)>,
161 ) -> LLVMType {
162 let name0 = name.as_ref();
163
164 let name = CString::new(name0).unwrap();
165 let mut et = element_type
166 .iter()
167 .map(|(_, t)| t.as_llvm_type_ref())
168 .collect::<Vec<LLVMTypeRef>>();
169 let t = unsafe { LLVMStructCreateNamed(self.llvm_ref, name.as_ptr()) };
170 unsafe {
171 LLVMStructSetBody(t, et.as_mut_ptr(), element_type.len() as c_uint, 0);
172 }
173 LLVMType::Struct(name0.into(), element_type, t)
174 }
175}
176
177impl Drop for LLVMContext {
178 fn drop(&mut self) {
179 unsafe { LLVMContextDispose(self.llvm_ref) };
180 }
181}