74af1b523550289731a9f30d4261c484dadce264
[kazan.git] / shader-compiler-llvm-7 / src / backend.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3 use llvm_sys;
4 use shader_compiler::backend::*;
5 use std::ffi::{CStr, CString};
6 use std::fmt;
7 use std::ops::Deref;
8 use std::os::raw::{c_char, c_uint};
9 use std::ptr::NonNull;
10
11 #[derive(Clone)]
12 pub struct LLVM7ShaderCompilerConfig {
13 pub variable_vector_length_multiplier: u32,
14 }
15
16 impl Default for LLVM7ShaderCompilerConfig {
17 fn default() -> Self {
18 Self {
19 variable_vector_length_multiplier: 1,
20 }
21 }
22 }
23
24 #[repr(transparent)]
25 struct LLVM7String(NonNull<c_char>);
26
27 impl Drop for LLVM7String {
28 fn drop(&mut self) {
29 unsafe {
30 llvm_sys::core::LLVMDisposeMessage(self.0.as_ptr());
31 }
32 }
33 }
34
35 impl Deref for LLVM7String {
36 type Target = CStr;
37 fn deref(&self) -> &CStr {
38 unsafe { CStr::from_ptr(self.0.as_ptr()) }
39 }
40 }
41
42 impl Clone for LLVM7String {
43 fn clone(&self) -> Self {
44 Self::new(self)
45 }
46 }
47
48 impl LLVM7String {
49 fn new(v: &CStr) -> Self {
50 unsafe { Self::from_ptr(llvm_sys::core::LLVMCreateMessage(v.as_ptr())).unwrap() }
51 }
52 unsafe fn from_nonnull(v: NonNull<c_char>) -> Self {
53 LLVM7String(v)
54 }
55 unsafe fn from_ptr(v: *mut c_char) -> Option<Self> {
56 NonNull::new(v).map(LLVM7String)
57 }
58 }
59
60 #[derive(Clone, Eq, PartialEq, Hash)]
61 #[repr(transparent)]
62 pub struct LLVM7Type(llvm_sys::prelude::LLVMTypeRef);
63
64 impl fmt::Debug for LLVM7Type {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 unsafe {
67 let string = LLVM7String::from_ptr(llvm_sys::core::LLVMPrintTypeToString(self.0))
68 .ok_or(fmt::Error)?;
69 f.write_str(&string.to_string_lossy())
70 }
71 }
72 }
73
74 impl<'a> Type<'a> for LLVM7Type {}
75
76 pub struct LLVM7TypeBuilder {
77 context: llvm_sys::prelude::LLVMContextRef,
78 variable_vector_length_multiplier: u32,
79 }
80
81 impl<'a> TypeBuilder<'a, LLVM7Type> for LLVM7TypeBuilder {
82 fn build_bool(&self) -> LLVM7Type {
83 unsafe { LLVM7Type(llvm_sys::core::LLVMInt1TypeInContext(self.context)) }
84 }
85 fn build_i8(&self) -> LLVM7Type {
86 unsafe { LLVM7Type(llvm_sys::core::LLVMInt8TypeInContext(self.context)) }
87 }
88 fn build_i16(&self) -> LLVM7Type {
89 unsafe { LLVM7Type(llvm_sys::core::LLVMInt16TypeInContext(self.context)) }
90 }
91 fn build_i32(&self) -> LLVM7Type {
92 unsafe { LLVM7Type(llvm_sys::core::LLVMInt32TypeInContext(self.context)) }
93 }
94 fn build_i64(&self) -> LLVM7Type {
95 unsafe { LLVM7Type(llvm_sys::core::LLVMInt64TypeInContext(self.context)) }
96 }
97 fn build_f32(&self) -> LLVM7Type {
98 unsafe { LLVM7Type(llvm_sys::core::LLVMFloatTypeInContext(self.context)) }
99 }
100 fn build_f64(&self) -> LLVM7Type {
101 unsafe { LLVM7Type(llvm_sys::core::LLVMDoubleTypeInContext(self.context)) }
102 }
103 fn build_pointer(&self, target: LLVM7Type) -> LLVM7Type {
104 unsafe { LLVM7Type(llvm_sys::core::LLVMPointerType(target.0, 0)) }
105 }
106 fn build_array(&self, element: LLVM7Type, count: usize) -> LLVM7Type {
107 assert_eq!(count as u32 as usize, count);
108 unsafe { LLVM7Type(llvm_sys::core::LLVMArrayType(element.0, count as u32)) }
109 }
110 fn build_vector(&self, element: LLVM7Type, length: VectorLength) -> LLVM7Type {
111 let length = match length {
112 VectorLength::Fixed { length } => length,
113 VectorLength::Variable { base_length } => base_length
114 .checked_mul(self.variable_vector_length_multiplier)
115 .unwrap(),
116 };
117 assert_ne!(length, 0);
118 unsafe { LLVM7Type(llvm_sys::core::LLVMVectorType(element.0, length)) }
119 }
120 fn build_struct(&self, members: &[LLVM7Type]) -> LLVM7Type {
121 assert_eq!(members.len() as c_uint as usize, members.len());
122 unsafe {
123 LLVM7Type(llvm_sys::core::LLVMStructTypeInContext(
124 self.context,
125 members.as_ptr() as *mut llvm_sys::prelude::LLVMTypeRef,
126 members.len() as c_uint,
127 false as llvm_sys::prelude::LLVMBool,
128 ))
129 }
130 }
131 fn build_function(&self, arguments: &[LLVM7Type], return_type: Option<LLVM7Type>) -> LLVM7Type {
132 assert_eq!(arguments.len() as c_uint as usize, arguments.len());
133 unsafe {
134 LLVM7Type(llvm_sys::core::LLVMFunctionType(
135 return_type
136 .unwrap_or_else(|| {
137 LLVM7Type(llvm_sys::core::LLVMVoidTypeInContext(self.context))
138 })
139 .0,
140 arguments.as_ptr() as *mut llvm_sys::prelude::LLVMTypeRef,
141 arguments.len() as c_uint,
142 false as llvm_sys::prelude::LLVMBool,
143 ))
144 }
145 }
146 }
147
148 pub struct LLVM7Context {
149 context: llvm_sys::prelude::LLVMContextRef,
150 config: LLVM7ShaderCompilerConfig,
151 }
152
153 impl Drop for LLVM7Context {
154 fn drop(&mut self) {
155 unsafe {
156 llvm_sys::core::LLVMContextDispose(self.context);
157 }
158 }
159 }
160
161 impl<'a> Context<'a> for LLVM7Context {
162 type Type = LLVM7Type;
163 type TypeBuilder = LLVM7TypeBuilder;
164 type Module = LLVM7Module;
165 type Builder = LLVM7Builder;
166 fn create_module(&self, name: &str) -> LLVM7Module {
167 let name = CString::new(name).unwrap();
168 unsafe {
169 LLVM7Module(llvm_sys::core::LLVMModuleCreateWithNameInContext(
170 name.as_ptr(),
171 self.context,
172 ))
173 }
174 }
175 fn create_builder(&self) -> LLVM7Builder {
176 unsafe { LLVM7Builder(llvm_sys::core::LLVMCreateBuilderInContext(self.context)) }
177 }
178 fn create_type_builder(&self) -> LLVM7TypeBuilder {
179 LLVM7TypeBuilder {
180 context: self.context,
181 variable_vector_length_multiplier: self.config.variable_vector_length_multiplier,
182 }
183 }
184 }
185
186 #[repr(transparent)]
187 pub struct LLVM7Builder(llvm_sys::prelude::LLVMBuilderRef);
188
189 impl Drop for LLVM7Builder {
190 fn drop(&mut self) {
191 unsafe {
192 llvm_sys::core::LLVMDisposeBuilder(self.0);
193 }
194 }
195 }
196
197 impl<'a> Builder<'a> for LLVM7Builder {}
198
199 #[repr(transparent)]
200 pub struct LLVM7Module(llvm_sys::prelude::LLVMModuleRef);
201
202 impl Drop for LLVM7Module {
203 fn drop(&mut self) {
204 unsafe {
205 llvm_sys::core::LLVMDisposeModule(self.0);
206 }
207 }
208 }
209
210 impl<'a> Module<'a> for LLVM7Module {
211 fn set_source_file_name(&mut self, source_file_name: &str) {
212 unsafe {
213 llvm_sys::core::LLVMSetSourceFileName(
214 self.0,
215 source_file_name.as_ptr() as *const c_char,
216 source_file_name.len(),
217 )
218 }
219 }
220 }
221
222 pub struct LLVM7ShaderCompiler;
223
224 impl ShaderCompiler for LLVM7ShaderCompiler {
225 type Config = LLVM7ShaderCompilerConfig;
226 fn name() -> &'static str {
227 "LLVM 7"
228 }
229 fn run_with_user<SCU: ShaderCompilerUser>(
230 shader_compiler_user: SCU,
231 config: LLVM7ShaderCompilerConfig,
232 ) -> SCU::ReturnType {
233 let context = unsafe {
234 LLVM7Context {
235 context: llvm_sys::core::LLVMContextCreate(),
236 config,
237 }
238 };
239 shader_compiler_user.run_with_context(&context)
240 }
241 }