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