implement creating functions and basic blocks
[kazan.git] / shader-compiler / src / parsed_shader_compile.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3
4 use super::{Context, IdKind, Ids, ParsedShader, ParsedShaderFunction};
5 use shader_compiler_backend::{
6 types::TypeBuilder, BuildableBasicBlock, DetachedBuilder, Function, Module,
7 };
8 use spirv_parser::Decoration;
9 use spirv_parser::{FunctionControl, IdRef, IdResult, IdResultType, Instruction};
10 use std::cell::Cell;
11 use std::collections::hash_map;
12 use std::collections::{HashMap, HashSet};
13 use std::hash::Hash;
14 use std::rc::Rc;
15
16 pub(crate) trait ParsedShaderCompile<'ctx, C: shader_compiler_backend::Context<'ctx>> {
17 fn compile(
18 self,
19 frontend_context: &mut Context,
20 backend_context: &'ctx C,
21 module: &mut C::Module,
22 function_name_prefix: &str,
23 ) -> C::Function;
24 }
25
26 struct Worklist<T> {
27 set: HashSet<T>,
28 list: Vec<T>,
29 }
30
31 impl<T: Eq + Hash + Clone> Worklist<T> {
32 fn get_next(&mut self) -> Option<T> {
33 self.list.pop()
34 }
35 fn add(&mut self, v: T) -> bool {
36 if self.set.insert(v.clone()) {
37 self.list.push(v);
38 true
39 } else {
40 false
41 }
42 }
43 }
44
45 impl<T: Eq + Hash + Clone> Default for Worklist<T> {
46 fn default() -> Self {
47 Self {
48 set: HashSet::new(),
49 list: Vec::new(),
50 }
51 }
52 }
53
54 struct FunctionInstruction {
55 id_result_type: IdResultType,
56 id_result: IdResult,
57 function_control: FunctionControl,
58 function_type: IdRef,
59 }
60
61 struct FunctionState<'ctx, C: shader_compiler_backend::Context<'ctx>> {
62 function_instruction: FunctionInstruction,
63 instructions: Vec<Instruction>,
64 decorations: Vec<Decoration>,
65 backend_function: Cell<Option<C::Function>>,
66 backend_function_value: C::Value,
67 }
68
69 struct GetOrAddFunctionState<'ctx, 'tb, 'fnp, C: shader_compiler_backend::Context<'ctx>>
70 where
71 C::TypeBuilder: 'tb,
72 {
73 reachable_functions: HashMap<IdRef, Rc<FunctionState<'ctx, C>>>,
74 type_builder: &'tb C::TypeBuilder,
75 function_name_prefix: &'fnp str,
76 }
77
78 impl<'ctx, 'tb, 'fnp, C: shader_compiler_backend::Context<'ctx>>
79 GetOrAddFunctionState<'ctx, 'tb, 'fnp, C>
80 {
81 fn call(
82 &mut self,
83 reachable_functions_worklist: &mut Vec<IdRef>,
84 ids: &mut Ids<'ctx, C>,
85 module: &mut C::Module,
86 function_id: IdRef,
87 ) -> Rc<FunctionState<'ctx, C>> {
88 match self.reachable_functions.entry(function_id) {
89 hash_map::Entry::Occupied(v) => v.get().clone(),
90 hash_map::Entry::Vacant(v) => {
91 reachable_functions_worklist.push(function_id);
92 let ParsedShaderFunction {
93 instructions,
94 decorations,
95 } = match &mut ids[function_id].kind {
96 IdKind::Function(function) => function.take().unwrap(),
97 _ => unreachable!("id is not a function"),
98 };
99 let function_instruction = match instructions.get(0) {
100 Some(&Instruction::Function {
101 id_result_type,
102 id_result,
103 ref function_control,
104 function_type,
105 }) => FunctionInstruction {
106 id_result_type,
107 id_result,
108 function_control: function_control.clone(),
109 function_type,
110 },
111 _ => unreachable!("missing OpFunction"),
112 };
113 for decoration in &decorations {
114 match decoration {
115 _ => unreachable!(
116 "unimplemented function decoration: {:?} on {}",
117 decoration, function_id
118 ),
119 }
120 }
121 let function_type = match &ids[function_instruction.function_type].kind {
122 IdKind::FunctionType {
123 return_type,
124 arguments,
125 } => {
126 let return_type = match return_type {
127 None => None,
128 Some(v) => unimplemented!(),
129 };
130 let arguments: Vec<_> = arguments
131 .iter()
132 .enumerate()
133 .map(|(argument_index, argument)| unimplemented!())
134 .collect();
135 self.type_builder.build_function(&arguments, return_type)
136 }
137 _ => unreachable!("not a function type"),
138 };
139 let backend_function = module.add_function(
140 &format!("{}{}", self.function_name_prefix, function_id.0),
141 function_type,
142 );
143 let backend_function_value = backend_function.as_value();
144 v.insert(Rc::new(FunctionState {
145 function_instruction,
146 instructions,
147 decorations,
148 backend_function: Cell::new(Some(backend_function)),
149 backend_function_value,
150 }))
151 .clone()
152 }
153 }
154 }
155 }
156
157 impl<'ctx, C: shader_compiler_backend::Context<'ctx>> ParsedShaderCompile<'ctx, C>
158 for ParsedShader<'ctx, C>
159 {
160 fn compile(
161 self,
162 frontend_context: &mut Context,
163 backend_context: &'ctx C,
164 module: &mut C::Module,
165 function_name_prefix: &str,
166 ) -> C::Function {
167 let ParsedShader {
168 mut ids,
169 main_function_id,
170 interface_variables,
171 execution_modes,
172 workgroup_size,
173 } = self;
174 let type_builder = backend_context.create_type_builder();
175 let mut reachable_functions_worklist = Vec::new();
176 let mut get_or_add_function_state = GetOrAddFunctionState {
177 reachable_functions: HashMap::new(),
178 type_builder: &type_builder,
179 function_name_prefix,
180 };
181 let mut get_or_add_function = |reachable_functions_worklist: &mut Vec<IdRef>,
182 ids: &mut Ids<'ctx, C>,
183 module: &mut C::Module,
184 function_id: IdRef| {
185 get_or_add_function_state.call(reachable_functions_worklist, ids, module, function_id)
186 };
187 let get_or_add_basic_block =
188 |ids: &mut Ids<'ctx, C>, label_id: IdRef, backend_function: &mut C::Function| {
189 if let IdKind::BasicBlock { basic_block, .. } = &ids[label_id].kind {
190 return basic_block.clone();
191 }
192 let buildable_basic_block =
193 backend_function.append_new_basic_block(Some(&format!("L{}", label_id.0)));
194 let basic_block = buildable_basic_block.as_basic_block();
195 ids[label_id].set_kind(IdKind::BasicBlock {
196 buildable_basic_block: Some(buildable_basic_block),
197 basic_block: basic_block.clone(),
198 });
199 basic_block
200 };
201 get_or_add_function(
202 &mut reachable_functions_worklist,
203 &mut ids,
204 module,
205 main_function_id,
206 );
207 while let Some(function_id) = reachable_functions_worklist.pop() {
208 let function_state = get_or_add_function(
209 &mut reachable_functions_worklist,
210 &mut ids,
211 module,
212 function_id,
213 );
214 let mut backend_function = function_state.backend_function.replace(None).unwrap();
215 enum BasicBlockState<'ctx, C: shader_compiler_backend::Context<'ctx>> {
216 Detached {
217 builder: C::DetachedBuilder,
218 },
219 Attached {
220 builder: C::AttachedBuilder,
221 current_label: IdRef,
222 },
223 }
224 let mut current_basic_block: BasicBlockState<C> = BasicBlockState::Detached {
225 builder: backend_context.create_builder(),
226 };
227 for instruction in &function_state.instructions {
228 match current_basic_block {
229 BasicBlockState::Attached {
230 builder,
231 current_label,
232 } => match instruction {
233 _ => unimplemented!("unimplemented instruction:\n{}", instruction),
234 },
235 BasicBlockState::Detached { builder } => match instruction {
236 Instruction::Function { .. } => {
237 current_basic_block = BasicBlockState::Detached { builder };
238 }
239 Instruction::Label { id_result } => {
240 ids[id_result.0].assert_no_decorations(id_result.0);
241 get_or_add_basic_block(&mut ids, id_result.0, &mut backend_function);
242 let buildable_basic_block = match ids[id_result.0].kind {
243 IdKind::BasicBlock {
244 ref mut buildable_basic_block,
245 ..
246 } => buildable_basic_block.take().expect("duplicate OpLabel"),
247 _ => unreachable!(),
248 };
249 current_basic_block = BasicBlockState::Attached {
250 builder: builder.attach(buildable_basic_block),
251 current_label: id_result.0,
252 };
253 }
254 _ => unimplemented!("unimplemented instruction:\n{}", instruction),
255 },
256 }
257 }
258 }
259 unimplemented!()
260 }
261 }