pipeline_script/llvm/
context.rs

1use 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        // 创建 MemoryBuffer
57        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        // 解析 IR
66        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            // 将 C 字符串指针转换为 Rust 字符串
82            let error_string = unsafe { CStr::from_ptr(*error_msg) };
83
84            // 将 CStr 转换为 Rust String
85            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}