1use std::collections;
2use std::usize;
3
4use specs;
5
6use ir::component::element;
7use ir::component::layout;
8use std::ops;
9
10pub struct System {
11 ptr_size: usize,
12}
13
14const BOOL_LAYOUT: layout::Layout = layout::Layout::scalar(1);
15
16impl<'a> specs::System<'a> for System {
17 type SystemData = (
18 specs::Entities<'a>,
19 specs::ReadStorage<'a, element::Element>,
20 specs::WriteStorage<'a, layout::Layout>,
21 );
22
23 fn run(&mut self, (entities, elements, mut layouts): Self::SystemData) {
24 use specs::prelude::ParallelIterator;
25 use specs::ParJoin;
26
27 loop {
28 let new_layouts = (&entities, &elements, !&layouts)
29 .par_join()
30 .flat_map(|(entity, element, _)| {
31 self.infer_layout(element, &elements, &layouts)
32 .map(|layout| (entity, layout))
33 })
34 .collect::<Vec<_>>();
35 debug!("inferred new layouts: {:?}", new_layouts);
36 if new_layouts.is_empty() {
37 break;
38 }
39
40 for (entity, layout) in new_layouts {
41 layouts.insert(entity, layout).unwrap();
42 }
43 }
44 }
45}
46
47impl System {
48 pub fn new(ptr_size: usize) -> System {
49 System { ptr_size }
50 }
51
52 fn infer_layout<DE, DL>(
53 &self,
54 element: &element::Element,
55 elements: &specs::Storage<element::Element, DE>,
56 layouts: &specs::Storage<layout::Layout, DL>,
57 ) -> Option<layout::Layout>
58 where
59 DE: ops::Deref<Target = specs::storage::MaskedStorage<element::Element>>,
60 DL: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
61 {
62 match *element {
63 element::Element::NumberValue(ref n) => self.infer_number_layout(n),
64 element::Element::StringValue(_) => Some(layout::Layout::scalar(self.ptr_size)),
65 element::Element::Tuple(element::Tuple { ref fields }) => {
66 self.infer_tuple_layout(fields, layouts)
67 }
68 element::Element::Record(element::Record { ref fields }) => {
69 self.infer_record_layout(fields, layouts)
70 }
71 element::Element::UnOp(element::UnOp { operator, operand }) => {
72 self.infer_un_op_layout(operator, operand, layouts)
73 }
74 element::Element::BiOp(element::BiOp { lhs, operator, rhs }) => {
75 self.infer_bi_op_layout(lhs, operator, rhs, layouts)
76 }
77 element::Element::Variable(element::Variable { initializer, .. }) => {
78 self.infer_variable_layout(initializer, layouts)
79 }
80 element::Element::Select(element::Select { record, ref field }) => {
81 self.infer_select_layout(record, field, elements, layouts)
82 }
83 element::Element::Apply(element::Apply {
84 function,
85 ref parameters,
86 }) => self.infer_apply_layout(function, parameters, layouts),
87 element::Element::Parameter(element::Parameter { signature, .. }) => {
88 self.infer_parameter_layout(signature, layouts)
89 }
90 element::Element::Capture(element::Capture { captured, .. }) => {
91 self.infer_capture_layout(captured, layouts)
92 }
93 element::Element::Closure(element::Closure {
94 ref parameters,
95 signature,
96 result,
97 ..
98 }) => self.infer_closure_layout(parameters, signature, result, layouts),
99 element::Element::Module(element::Module { ref variables }) => {
100 self.infer_module_layout(variables, layouts)
101 }
102 }
103 }
104
105 fn infer_number_layout(&self, number: &element::NumberValue) -> Option<layout::Layout> {
106 match *number {
107 element::NumberValue::U8(_) => Some(layout::Layout::scalar(1)),
108 element::NumberValue::U16(_) => Some(layout::Layout::scalar(2)),
109 element::NumberValue::U32(_) => Some(layout::Layout::scalar(4)),
110 element::NumberValue::U64(_) => Some(layout::Layout::scalar(8)),
111 element::NumberValue::I8(_) => Some(layout::Layout::scalar(1)),
112 element::NumberValue::I16(_) => Some(layout::Layout::scalar(2)),
113 element::NumberValue::I32(_) => Some(layout::Layout::scalar(4)),
114 element::NumberValue::I64(_) => Some(layout::Layout::scalar(8)),
115 element::NumberValue::F32(_) => Some(layout::Layout::scalar(4)),
116 element::NumberValue::F64(_) => Some(layout::Layout::scalar(8)),
117 }
118 }
119
120 fn infer_tuple_layout<D>(
121 &self,
122 fields: &[specs::Entity],
123 layouts: &specs::Storage<layout::Layout, D>,
124 ) -> Option<layout::Layout>
125 where
126 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
127 {
128 if let Some(mut layouts) = fields
129 .iter()
130 .enumerate()
131 .map(|(i, f)| layouts.get(*f).map(|l| (i, l)))
132 .collect::<Option<Vec<_>>>()
133 {
134 if layouts.is_empty() {
135 Some(layout::Layout::zero())
136 } else {
137 layouts.sort_unstable_by_key(|(i, l)| (usize::MAX - l.size, *i));
138 let alignment = layouts.iter().map(|(_, l)| l.alignment).max().unwrap();
139 let mut size = 0;
140
141 let mut unnamed_field_offsets = vec![0; layouts.len()];
142
143 for (i, layout) in layouts {
144 let offset = align_up(size, layout.alignment);
145 size = offset + layout.size;
146 unnamed_field_offsets[i] = offset;
147 }
148
149 Some(layout::Layout::unnamed_fields(
150 size,
151 alignment,
152 unnamed_field_offsets,
153 ))
154 }
155 } else {
156 None
157 }
158 }
159
160 fn infer_record_layout<D>(
161 &self,
162 fields: &collections::HashMap<String, specs::Entity>,
163 layouts: &specs::Storage<layout::Layout, D>,
164 ) -> Option<layout::Layout>
165 where
166 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
167 {
168 if let Some(mut layouts) = fields
169 .iter()
170 .map(|(n, f)| layouts.get(*f).map(|l| (n, l)))
171 .collect::<Option<Vec<_>>>()
172 {
173 if layouts.is_empty() {
174 Some(layout::Layout::zero())
175 } else {
176 layouts.sort_unstable_by_key(|(n, l)| (usize::MAX - l.size, n.as_str()));
177 let alignment = layouts.iter().map(|(_, l)| l.alignment).max().unwrap();
178 let mut size = 0;
179
180 let named_field_offsets = layouts
181 .into_iter()
182 .map(|(n, l)| {
183 let offset = align_up(size, l.alignment);
184 size = offset + l.size;
185 (n.clone(), offset)
186 })
187 .collect::<collections::HashMap<_, _>>();
188
189 Some(layout::Layout::named_fields(
190 size,
191 alignment,
192 named_field_offsets,
193 ))
194 }
195 } else {
196 None
197 }
198 }
199
200 fn infer_un_op_layout<D>(
201 &self,
202 operator: element::UnOperator,
203 operand: specs::Entity,
204 layouts: &specs::Storage<layout::Layout, D>,
205 ) -> Option<layout::Layout>
206 where
207 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
208 {
209 let operand = layouts.get(operand).cloned();
210
211 match operator {
212 element::UnOperator::Not => Some(BOOL_LAYOUT),
213 element::UnOperator::BNot => operand,
214 element::UnOperator::Cl0 => operand,
215 element::UnOperator::Cl1 => operand,
216 element::UnOperator::Cls => operand,
217 element::UnOperator::Ct0 => operand,
218 element::UnOperator::Ct1 => operand,
219 element::UnOperator::C0 => operand,
220 element::UnOperator::C1 => operand,
221 element::UnOperator::Sqrt => operand,
222 }
223 }
224
225 fn infer_bi_op_layout<D>(
226 &self,
227 lhs: specs::Entity,
228 operator: element::BiOperator,
229 rhs: specs::Entity,
230 layouts: &specs::Storage<layout::Layout, D>,
231 ) -> Option<layout::Layout>
232 where
233 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
234 {
235 let lhs = layouts.get(lhs).cloned();
236 let rhs = layouts.get(rhs).cloned();
237
238 match (lhs.as_ref(), rhs.as_ref()) {
239 (Some(lhs), Some(rhs)) => {
240 assert_eq!(lhs.size, rhs.size);
241 assert_eq!(lhs.alignment, rhs.alignment);
242 }
243 _ => (),
244 };
245
246 match operator {
247 element::BiOperator::Eq => Some(BOOL_LAYOUT),
248 element::BiOperator::Ne => Some(BOOL_LAYOUT),
249 element::BiOperator::Lt => Some(BOOL_LAYOUT),
250 element::BiOperator::Ge => Some(BOOL_LAYOUT),
251 element::BiOperator::Gt => Some(BOOL_LAYOUT),
252 element::BiOperator::Le => Some(BOOL_LAYOUT),
253 element::BiOperator::Cmp => unimplemented!(),
254 element::BiOperator::Add => lhs,
255 element::BiOperator::Sub => lhs,
256 element::BiOperator::Mul => lhs,
257 element::BiOperator::Div => lhs,
258 element::BiOperator::Rem => lhs,
259 element::BiOperator::And => Some(BOOL_LAYOUT),
260 element::BiOperator::BAnd => lhs,
261 element::BiOperator::Or => Some(BOOL_LAYOUT),
262 element::BiOperator::BOr => lhs,
263 element::BiOperator::Xor => Some(BOOL_LAYOUT),
264 element::BiOperator::BXor => lhs,
265 element::BiOperator::AndNot => Some(BOOL_LAYOUT),
266 element::BiOperator::BAndNot => lhs,
267 element::BiOperator::OrNot => Some(BOOL_LAYOUT),
268 element::BiOperator::BOrNot => lhs,
269 element::BiOperator::XorNot => Some(BOOL_LAYOUT),
270 element::BiOperator::BXorNot => lhs,
271 element::BiOperator::RotL => lhs,
272 element::BiOperator::RotR => lhs,
273 element::BiOperator::ShL => lhs,
274 element::BiOperator::ShR => lhs,
275 }
276 }
277
278 fn infer_variable_layout<D>(
279 &self,
280 initializer: specs::Entity,
281 layouts: &specs::Storage<layout::Layout, D>,
282 ) -> Option<layout::Layout>
283 where
284 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
285 {
286 layouts.get(initializer).cloned()
287 }
288
289 fn infer_select_layout<DE, DL>(
290 &self,
291 record: specs::Entity,
292 field: &str,
293 elements: &specs::Storage<element::Element, DE>,
294 layouts: &specs::Storage<layout::Layout, DL>,
295 ) -> Option<layout::Layout>
296 where
297 DE: ops::Deref<Target = specs::storage::MaskedStorage<element::Element>>,
298 DL: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
299 {
300 match elements.get(record) {
301 None => None,
302 Some(t) => match t {
303 element::Element::Record(element::Record { ref fields }) => {
304 if let Some(f) = fields.get(field) {
305 layouts.get(*f).cloned()
306 } else {
307 None
308 }
309 }
310 _ => None,
311 },
312 }
313 }
314
315 fn infer_apply_layout<D>(
316 &self,
317 _function: specs::Entity,
318 _parameters: &[specs::Entity],
319 _layouts: &specs::Storage<layout::Layout, D>,
320 ) -> Option<layout::Layout>
321 where
322 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
323 {
324 None
326 }
368
369 fn infer_parameter_layout<D>(
370 &self,
371 _signature: Option<specs::Entity>,
372 _layouts: &specs::Storage<layout::Layout, D>,
373 ) -> Option<layout::Layout>
374 where
375 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
376 {
377 None
379 }
389
390 fn infer_capture_layout<D>(
391 &self,
392 capture: specs::Entity,
393 layouts: &specs::Storage<layout::Layout, D>,
394 ) -> Option<layout::Layout>
395 where
396 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
397 {
398 layouts.get(capture).cloned()
399 }
400
401 fn infer_closure_layout<D>(
402 &self,
403 _parameters: &[specs::Entity],
404 _signature: Option<specs::Entity>,
405 _result: specs::Entity,
406 _layouts: &specs::Storage<layout::Layout, D>,
407 ) -> Option<layout::Layout>
408 where
409 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
410 {
411 None
413 }
441
442 fn infer_module_layout<D>(
443 &self,
444 _variables: &collections::HashMap<String, specs::Entity>,
445 _layouts: &specs::Storage<layout::Layout, D>,
446 ) -> Option<layout::Layout>
447 where
448 D: ops::Deref<Target = specs::storage::MaskedStorage<layout::Layout>>,
449 {
450 None
452 }
460}
461
462fn align_up(offset: usize, alignment: usize) -> usize {
463 debug_assert!(alignment.is_power_of_two());
464 offset + ((-(offset as isize)) & (alignment as isize - 1)) as usize
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 #[test]
472 fn align_up_4() {
473 assert_eq!(0, align_up(0, 4));
474 assert_eq!(4, align_up(1, 4));
475 assert_eq!(4, align_up(2, 4));
476 assert_eq!(4, align_up(3, 4));
477 assert_eq!(4, align_up(4, 4));
478 assert_eq!(8, align_up(5, 4));
479 assert_eq!(8, align_up(6, 4));
480 assert_eq!(8, align_up(7, 4));
481 assert_eq!(8, align_up(8, 4));
482 assert_eq!(12, align_up(9, 4));
483 }
484
485 #[test]
486 fn align_up_8() {
487 assert_eq!(0, align_up(0, 8));
488 assert_eq!(8, align_up(1, 8));
489 assert_eq!(8, align_up(2, 8));
490 assert_eq!(8, align_up(3, 8));
491 assert_eq!(8, align_up(4, 8));
492 assert_eq!(8, align_up(5, 8));
493 assert_eq!(8, align_up(6, 8));
494 assert_eq!(8, align_up(7, 8));
495 assert_eq!(8, align_up(8, 8));
496 assert_eq!(16, align_up(9, 8));
497 }
498}