format source
[kazan.git] / shader-compiler-backend / src / lib.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3 #![deny(missing_docs)]
4
5 //! Shader Compiler Backend Traits for Kazan
6
7 use std::collections::HashMap;
8 use std::error::Error;
9 use std::fmt;
10 use std::fmt::Debug;
11 use std::hash::Hash;
12 use std::io;
13 use std::marker::PhantomData;
14
15 #[macro_use]
16 pub mod types;
17
18 /// equivalent to LLVM's 'IRBuilder'
19 pub trait AttachedBuilder<'a>: Sized {
20 /// the `Context` type
21 type Context: Context<'a>;
22 /// get the current `BasicBlock`
23 fn current_basic_block(&self) -> <Self::Context as Context<'a>>::BasicBlock;
24 /// build an alloca instruction
25 fn build_alloca(
26 &mut self,
27 variable_type: <Self::Context as Context<'a>>::Type,
28 ) -> <Self::Context as Context<'a>>::Value;
29 /// build a return instruction
30 fn build_return(
31 self,
32 value: Option<<Self::Context as Context<'a>>::Value>,
33 ) -> <Self::Context as Context<'a>>::DetachedBuilder;
34 }
35
36 /// equivalent to LLVM's 'IRBuilder'
37 pub trait DetachedBuilder<'a>: Sized {
38 /// the `Context` type
39 type Context: Context<'a>;
40 /// attach `basic_block` to `Self`, converting into an `AttachedBuilder`
41 fn attach(
42 self,
43 basic_block: <Self::Context as Context<'a>>::BuildableBasicBlock,
44 ) -> <Self::Context as Context<'a>>::AttachedBuilder;
45 }
46
47 /// equivalent to LLVM's 'Value'
48 pub trait Value<'a>: Clone + Debug {
49 /// the `Context` type
50 type Context: Context<'a>;
51 }
52
53 /// equivalent to LLVM's 'BasicBlock'
54 pub trait BasicBlock<'a>: Clone + Debug {
55 /// the `Context` type
56 type Context: Context<'a>;
57 /// get the `Value` corresponding to `Self`
58 fn as_value(&self) -> <Self::Context as Context<'a>>::Value;
59 }
60
61 /// equivalent to LLVM's 'BasicBlock'
62 pub trait BuildableBasicBlock<'a>: Debug + Sized {
63 /// the `Context` type
64 type Context: Context<'a>;
65 /// get the `BasicBlock` corresponding to `Self`
66 fn as_basic_block(&self) -> <Self::Context as Context<'a>>::BasicBlock;
67 /// get the `Value` corresponding to `Self`
68 fn as_value(&self) -> <Self::Context as Context<'a>>::Value {
69 self.as_basic_block().as_value()
70 }
71 }
72
73 /// equivalent to LLVM's 'Function'
74 pub trait Function<'a>: Debug + Sized {
75 /// the `Context` type
76 type Context: Context<'a>;
77 /// get the `Value` corresponding to `Self`
78 fn as_value(&self) -> <Self::Context as Context<'a>>::Value;
79 /// append a new `BasicBlock` to `Self`
80 fn append_new_basic_block(
81 &mut self,
82 name: Option<&str>,
83 ) -> <Self::Context as Context<'a>>::BuildableBasicBlock;
84 /// get this function's parameters
85 fn parameters(&self) -> &[<Self::Context as Context<'a>>::Value];
86 }
87
88 /// module verification failure; returned from `Module::verify`
89 pub struct VerificationFailure<'a, M: Module<'a>> {
90 module: M,
91 message: String,
92 _phantom_data: PhantomData<&'a ()>,
93 }
94
95 impl<'a, M: Module<'a>> VerificationFailure<'a, M> {
96 /// create a new `VerificationFailure`
97 pub fn new<T: ToString + ?Sized>(module: M, message: &T) -> Self {
98 VerificationFailure {
99 module,
100 message: message.to_string(),
101 _phantom_data: PhantomData,
102 }
103 }
104 /// get the `Module` that failed verification
105 pub fn into_module(self) -> M {
106 self.module
107 }
108 }
109
110 impl<'a, M: Module<'a>> fmt::Display for VerificationFailure<'a, M> {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 write!(f, "module verification failure: {}", self.message,)
113 }
114 }
115
116 impl<'a, M: Module<'a>> Debug for VerificationFailure<'a, M> {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 f.debug_struct("VerificationFailure")
119 .field("message", &self.message)
120 .field("module", &self.module)
121 .finish()
122 }
123 }
124
125 impl<'a, M: Module<'a>> Error for VerificationFailure<'a, M> {}
126
127 impl<'a, M: Module<'a>> From<VerificationFailure<'a, M>> for io::Error {
128 fn from(v: VerificationFailure<'a, M>) -> Self {
129 io::Error::new(io::ErrorKind::Other, format!("{}", v))
130 }
131 }
132
133 /// equivalent to LLVM's 'Module'
134 pub trait Module<'a>: Debug + Sized {
135 /// the `Context` type
136 type Context: Context<'a>;
137 /// set's the source file name for this module
138 fn set_source_file_name(&mut self, source_file_name: &str);
139 /// add a new empty function to `Self`
140 fn add_function(
141 &mut self,
142 name: &str,
143 ty: <Self::Context as Context<'a>>::Type,
144 ) -> <Self::Context as Context<'a>>::Function;
145 /// verify `Self`, converting into a `VerifiedModule`
146 fn verify(
147 self,
148 ) -> Result<<Self::Context as Context<'a>>::VerifiedModule, VerificationFailure<'a, Self>>;
149 /// convert into a `VerifiedModule` without verifing
150 unsafe fn to_verified_module_unchecked(self) -> <Self::Context as Context<'a>>::VerifiedModule;
151 }
152
153 /// equivalent to LLVM's 'Module'; create using `Module::verify` or `Module::to_verified_module_unchecked`
154 pub trait VerifiedModule<'a>: Debug + Sized {
155 /// the `Context` type
156 type Context: Context<'a>;
157 /// convert back to an unverified module
158 fn into_module(self) -> <Self::Context as Context<'a>>::Module;
159 }
160
161 /// instance of a compiler backend; equivalent to LLVM's `LLVMContext`
162 pub trait Context<'a>: Sized + fmt::Debug {
163 /// the `Value` type
164 type Value: Value<'a, Context = Self>;
165 /// the `BasicBlock` type
166 type BasicBlock: BasicBlock<'a, Context = Self>;
167 /// the `BuildableBasicBlock` type
168 type BuildableBasicBlock: BuildableBasicBlock<'a, Context = Self>;
169 /// the `Function` type
170 type Function: Function<'a, Context = Self>;
171 /// the `Module` type
172 type Module: Module<'a, Context = Self>;
173 /// the `VerifiedModule` type
174 type VerifiedModule: VerifiedModule<'a, Context = Self>;
175 /// the `AttachedBuilder` type
176 type AttachedBuilder: AttachedBuilder<'a, Context = Self>;
177 /// the `DetachedBuilder` type
178 type DetachedBuilder: DetachedBuilder<'a, Context = Self>;
179 /// the `Type` type
180 type Type: types::Type<'a, Context = Self>;
181 /// the `TypeBuilder` type
182 type TypeBuilder: types::TypeBuilder<'a, Self::Type>;
183 /// create a new `Module`
184 fn create_module(&self, name: &str) -> Self::Module;
185 /// create a new `DetachedBuilder`
186 fn create_builder(&self) -> Self::DetachedBuilder;
187 /// create a new `TypeBuilder`
188 fn create_type_builder(&self) -> Self::TypeBuilder;
189 }
190
191 /// inputs to the final compilation
192 pub struct CompileInputs<'a, C: Context<'a>, K: Hash + Eq + Send + Sync + 'static> {
193 /// the input module
194 pub module: C::VerifiedModule,
195 /// the list of functions that can be called from the final `CompiledCode`
196 pub callable_functions: HashMap<K, C::Function>,
197 }
198
199 /// the final compiled code
200 pub trait CompiledCode<K: Hash + Eq + Send + Sync + 'static>: Send + Sync {
201 /// get a function in the final compiled code.
202 /// the returned function needs to be cast to the correct type and
203 /// `Self` needs to still exist while the returned function exists
204 fn get(&self, which: &K) -> Option<unsafe extern "C" fn()>;
205 }
206
207 /// trait that the user of `Compiler` implements
208 pub trait CompilerUser {
209 /// the type used as a key for visible functions
210 type FunctionKey: Hash + Eq + Send + Sync + 'static;
211 /// the user's error type
212 type Error;
213 /// create an instance of `Error`
214 fn create_error(message: String) -> Self::Error;
215 /// the function that the user of `Compiler` implements
216 fn run<'a, C: Context<'a>>(
217 self,
218 context: &'a C,
219 ) -> Result<CompileInputs<'a, C, Self::FunctionKey>, Self::Error>;
220 }
221
222 /// optimization mode
223 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
224 pub enum OptimizationMode {
225 /// no optimizations are enabled
226 NoOptimizations,
227 /// default optimizations are enabled
228 Normal,
229 }
230
231 impl Default for OptimizationMode {
232 fn default() -> Self {
233 OptimizationMode::Normal
234 }
235 }
236
237 /// compiler independent config options
238 #[derive(Clone, Debug, Default)]
239 pub struct CompilerIndependentConfig {
240 /// optimization mode
241 pub optimization_mode: OptimizationMode,
242 }
243
244 /// main compiler backend trait
245 pub trait Compiler: Copy + Send + Sync + 'static {
246 /// the compiler's configuration
247 type Config: Default + Clone + From<CompilerIndependentConfig> + Send + Sync;
248 /// get shader compiler's name
249 fn name(self) -> &'static str;
250 /// run a passed-in function with a new compiler context.
251 /// this round-about method is used because generic associated types are not in stable Rust yet
252 fn run<U: CompilerUser>(
253 self,
254 user: U,
255 config: Self::Config,
256 ) -> Result<Box<dyn CompiledCode<U::FunctionKey>>, U::Error>;
257 }
258
259 #[cfg(test)]
260 mod test {
261 #![allow(dead_code)]
262
263 buildable_struct! {
264 struct S1 {
265 }
266 }
267
268 buildable_struct! {
269 pub struct S2 {
270 v: u32,
271 }
272 }
273
274 buildable_struct! {
275 struct S3 {
276 p: *mut S2,
277 v: ::types::VecNx4<f32>,
278 }
279 }
280 }