1use crate::ast::{
3 BinaryExprType, BuiltinExpr, DeclarationType, ExprType, Index, IndexType, OffsetofType, Span,
4 TypeExprType, UnaryExprType,
5};
6use crate::{ast, to_span, S};
7use anyhow::{anyhow, Result};
8use repc_impl::layout::{
9 Annotation, Array, FieldLayout, Layout, Record, RecordField, Type, TypeLayout, TypeVariant,
10};
11use repc_impl::target::Target;
12use repc_impl::util::BITS_PER_BYTE;
13use std::collections::{HashMap, HashSet};
14use std::convert::TryInto;
15use std::ops::Not;
16
17#[derive(Eq, PartialEq)]
18pub struct ConversionResult {
19 pub types: HashMap<String, Type<TypeLayout>>,
20 pub consts: HashMap<String, i128>,
21}
22
23pub fn extract_layouts(input: &str, d: &[ast::Declaration]) -> Result<ConversionResult> {
24 struct Converter<'a>(&'a str);
25 impl<'a> Convert for Converter<'a> {
26 type Src = TypeLayout;
27 const USE_EVALUATED_EXPR: bool = true;
28
29 fn convert(&self, ty: Type<Self::Src>) -> Result<Type<TypeLayout>> {
30 Ok(ty)
31 }
32
33 fn extract_type(&self, t: &ast::Type) -> Result<Self::Src> {
34 match t.layout {
35 None => Err(anyhow!(
36 "At {}: Missing type layout",
37 to_span(self.0, Span(t.lo, t.lo))
38 )),
39 Some(l) => Ok(l),
40 }
41 }
42
43 fn extract_field(&self, t: &ast::RecordField, _pos: usize) -> Result<FieldLayout> {
44 match t.layout {
45 None => Err(anyhow!(
46 "At {}: Missing field layout",
47 to_span(self.0, Span(t.lo, t.lo))
48 )),
49 Some(l) => Ok(l),
50 }
51 }
52 }
53 Computer::new(input, d, Converter(input))?.compute_layouts()
54}
55
56pub fn compute_layouts(
57 input: &str,
58 d: &[ast::Declaration],
59 target: Target,
60) -> Result<ConversionResult> {
61 struct Converter(Target);
62 impl Convert for Converter {
63 type Src = ();
64
65 fn convert(&self, ty: Type<Self::Src>) -> Result<Type<TypeLayout>> {
66 Ok(repc_impl::builder::compute_layout(self.0, &ty)?)
67 }
68
69 fn extract_type(&self, _: &ast::Type) -> Result<Self::Src> {
70 Ok(())
71 }
72
73 fn extract_field(&self, _: &ast::RecordField, _: usize) -> Result<()> {
74 Ok(())
75 }
76 }
77 Computer::new(input, d, Converter(target))?.compute_layouts()
78}
79
80pub trait Convert {
81 type Src: Layout<OpaqueLayout = TypeLayout>;
82 const USE_EVALUATED_EXPR: bool = false;
83
84 fn convert(&self, ty: Type<Self::Src>) -> Result<Type<TypeLayout>>;
85 fn extract_type(&self, ty: &ast::Type) -> Result<<Self::Src as Layout>::TypeLayout>;
86 fn extract_field(
87 &self,
88 field: &ast::RecordField,
89 pos: usize,
90 ) -> Result<<Self::Src as Layout>::FieldLayout>;
91}
92
93pub struct Computer<'a, C> {
94 input: &'a str,
95 d: &'a [ast::Declaration],
96 declarations: HashMap<&'a str, &'a ast::Declaration>,
97 type_layouts: HashMap<String, Type<TypeLayout>>,
98 constants: HashMap<String, i128>,
99 converting: HashSet<&'a str>,
100 converter: C,
101}
102
103impl<'a, C: Convert> Computer<'a, C> {
104 pub fn new(input: &'a str, d: &'a [ast::Declaration], converter: C) -> Result<Self> {
105 let mut declarations = HashMap::new();
106 for d in d {
107 if let Some(old) = declarations.insert(&*d.name, d) {
108 return Err(anyhow!(
109 "At {}: Type {} is declared multiple times. Previous declaration at {}",
110 to_span(input, d.span),
111 d.name,
112 to_span(input, old.span)
113 ));
114 }
115 }
116 Ok(Computer {
117 input,
118 d,
119 declarations,
120 converter,
121 type_layouts: Default::default(),
122 converting: Default::default(),
123 constants: Default::default(),
124 })
125 }
126
127 pub fn compute_layouts(mut self) -> Result<ConversionResult> {
128 for d in self.d {
129 match d.ty {
130 DeclarationType::Type(_) => {
131 self.compute_decl_ty_layout(d, d.span)?;
132 }
133 DeclarationType::Const(_) => {
134 self.compute_decl_const(d, d.span)?;
135 }
136 }
137 }
138 Ok(ConversionResult {
139 types: self.type_layouts,
140 consts: self.constants,
141 })
142 }
143
144 fn span(&self, span: Span) -> S {
145 to_span(self.input, span)
146 }
147
148 fn compute_decl_const(&mut self, d: &'a ast::Declaration, site: Span) -> Result<i128> {
149 if let Some(value) = self.constants.get(&d.name) {
150 return Ok(*value);
151 }
152 if self.converting.insert(&d.name).not() {
153 return Err(anyhow!(
154 "At {}: The value of {} depends on itself",
155 self.span(d.span),
156 d.name
157 ));
158 }
159 let e = match &d.ty {
160 DeclarationType::Type(_) => {
161 return Err(anyhow!(
162 "At {}: {} is declared as a type but must be a constant at {}",
163 self.span(d.span),
164 d.name,
165 self.span(site),
166 ));
167 }
168 DeclarationType::Const(e) => e,
169 };
170 let res = self.eval_expr(e);
171 self.converting.remove(&*d.name);
172 let res = res?;
173 self.constants.insert(d.name.clone(), res);
174 Ok(res)
175 }
176
177 fn compute_decl_ty_layout(
178 &mut self,
179 d: &'a ast::Declaration,
180 site: Span,
181 ) -> Result<TypeLayout> {
182 if let Some(layout) = self.type_layouts.get(&d.name) {
183 return Ok(layout.layout);
184 }
185 let ty = match &d.ty {
186 DeclarationType::Type(ty) => ty,
187 DeclarationType::Const(_) => {
188 return Err(anyhow!(
189 "At {}: {} is declared as a constant but must be a type at {}",
190 self.span(d.span),
191 d.name,
192 self.span(site),
193 ));
194 }
195 };
196 if self.converting.insert(&d.name).not() {
197 return Err(anyhow!(
198 "At {}: The layout of {} depends on itself",
199 self.span(d.span),
200 d.name
201 ));
202 }
203 let res = self.compute_type_layout(ty);
204 self.converting.remove(&*d.name);
205 let res = res?;
206 let layout = res.layout;
207 self.type_layouts.insert(d.name.clone(), res);
208 Ok(layout)
209 }
210
211 fn compute_type_layout(&mut self, t: &'a ast::Type) -> Result<Type<TypeLayout>> {
212 let t = self.convert_type(t)?;
213 Ok(self.converter.convert(t)?)
214 }
215
216 fn convert_type(&mut self, t: &'a ast::Type) -> Result<Type<C::Src>> {
217 let variant = match &t.variant {
218 ast::TypeVariant::Opaque(l) => {
219 let layout = if C::USE_EVALUATED_EXPR && t.layout.is_some() {
220 t.layout.unwrap()
221 } else {
222 TypeLayout {
223 size_bits: self.eval_u64_expr(&l.size_bits)?,
224 pointer_alignment_bits: self.eval_u64_expr(&l.pointer_alignment_bits)?,
225 field_alignment_bits: self.eval_u64_expr(&l.field_alignment_bits)?,
226 required_alignment_bits: self.eval_u64_expr(&l.required_alignment_bits)?,
227 }
228 };
229 TypeVariant::Opaque(layout)
230 }
231 ast::TypeVariant::Builtin(bi) => TypeVariant::Builtin(*bi),
232 ast::TypeVariant::Record(r) => TypeVariant::Record(self.convert_record(r)?),
233 ast::TypeVariant::Array(a) => TypeVariant::Array(self.convert_array(a)?),
234 ast::TypeVariant::Name(n, span) => match self.declarations.get(&**n) {
235 None => {
236 return Err(anyhow!(
237 "At {}: The referenced type {} is not declared",
238 self.span(*span),
239 n
240 ))
241 }
242 Some(&d) => TypeVariant::Opaque(self.compute_decl_ty_layout(d, *span)?),
243 },
244 ast::TypeVariant::Typedef(td) => TypeVariant::Typedef(Box::new(self.convert_type(td)?)),
245 ast::TypeVariant::Enum(e) => {
246 let mut res = vec![];
247 for e in e {
248 res.push(self.eval_expr(e)?);
249 }
250 TypeVariant::Enum(res)
251 }
252 };
253 Ok(Type {
254 layout: self.converter.extract_type(t)?,
255 annotations: self.convert_annotations(&t.annotations)?,
256 variant,
257 })
258 }
259
260 fn convert_record(&mut self, r: &'a ast::Record) -> Result<Record<C::Src>> {
261 let mut fields = vec![];
262 for f in &r.fields {
263 fields.push(self.convert_record_field(f)?);
264 }
265 Ok(Record {
266 kind: r.kind,
267 fields,
268 })
269 }
270
271 fn convert_record_field(&mut self, f: &'a ast::RecordField) -> Result<RecordField<C::Src>> {
272 Ok(RecordField {
273 layout: match f.pos {
274 Some(p) => Some(self.converter.extract_field(f, p)?),
275 _ => None,
276 },
277 annotations: self.convert_annotations(&f.annotations)?,
278 named: f.name.is_some(),
279 bit_width: f
280 .bit_width
281 .as_ref()
282 .map(|w| self.eval_u64_expr(w))
283 .transpose()?,
284 ty: self.convert_type(&f.ty)?,
285 })
286 }
287
288 fn convert_annotations(&mut self, a: &'a [ast::Annotation]) -> Result<Vec<Annotation>> {
289 let mut res = vec![];
290 for a in a {
291 res.push(match a {
292 ast::Annotation::PragmaPack(e) => {
293 Annotation::PragmaPack(BITS_PER_BYTE * self.eval_u64_expr(e)?)
294 }
295 ast::Annotation::AttrPacked => Annotation::AttrPacked,
296 ast::Annotation::Aligned(None) => Annotation::Align(None),
297 ast::Annotation::Aligned(Some(e)) => {
298 Annotation::Align(Some(BITS_PER_BYTE * self.eval_u64_expr(e)?))
299 }
300 });
301 }
302 Ok(res)
303 }
304
305 fn eval_u64_expr(&mut self, e: &'a ast::Expr) -> Result<u64> {
306 let v = self.eval_expr(e)?.try_into().map_err(|_| {
307 anyhow!(
308 "At {}: Expression value does not fit into u64",
309 self.span(e.span)
310 )
311 })?;
312 Ok(v)
313 }
314
315 fn eval_expr(&mut self, e: &'a ast::Expr) -> Result<i128> {
316 if C::USE_EVALUATED_EXPR {
317 if let Some(e) = e.value {
318 return Ok(e);
319 }
320 }
321 match &e.ty {
322 ExprType::Lit(n) => Ok(*n),
323 ExprType::Builtin(b) => match b {
324 BuiltinExpr::BitsPerByte => Ok(BITS_PER_BYTE as i128),
325 },
326 ExprType::Unary(k, v) => {
327 let v = self.eval_expr(v)?;
328 match *k {
329 UnaryExprType::Neg => v
330 .checked_neg()
331 .ok_or_else(|| anyhow!("At {}: Expression overflow", self.span(e.span))),
332 UnaryExprType::Not => Ok(if v != 0 { 0 } else { 1 }),
333 }
334 }
335 ExprType::Binary(k, le, re) => {
336 use BinaryExprType::*;
337 let l = self.eval_expr(le)?;
338 let r = self.eval_expr(re)?;
339 match *k {
340 Add | Sub | Mul => match *k {
341 Add => l.checked_add(r),
342 Sub => l.checked_sub(r),
343 Mul => l.checked_mul(r),
344 _ => unreachable!(),
345 }
346 .ok_or_else(|| anyhow!("At {}: Expression overflow", self.span(e.span))),
347 Div | Mod => {
348 if r == 0 {
349 return Err(anyhow!("At {}: Division by zero", self.span(re.span)));
350 }
351 Ok(match *k {
352 Div => l / r,
353 Mod => l % r,
354 _ => unreachable!(),
355 })
356 }
357 LogicalAnd | LogicalOr | Eq | NotEq | Lt | Le | Gt | Ge => {
358 let ll = l != 0;
359 let rr = r != 0;
360 Ok(match *k {
361 LogicalAnd => ll && rr,
362 LogicalOr => ll || rr,
363 Eq => l == r,
364 NotEq => l != r,
365 Lt => l < r,
366 Le => l <= r,
367 Gt => l > r,
368 Ge => l >= r,
369 _ => unreachable!(),
370 } as i128)
371 }
372 }
373 }
374 ExprType::TypeExpr(k, t) => {
375 let layout = self.compute_type_layout(t)?.layout;
376 Ok(match k {
377 TypeExprType::Sizeof => (layout.size_bits / BITS_PER_BYTE) as i128,
378 TypeExprType::SizeofBits => layout.size_bits as i128,
379 })
380 }
381 ExprType::Name(n) => match self.declarations.get(&**n) {
382 None => Err(anyhow!(
383 "At {}: The referenced constant {} is not declared",
384 self.span(e.span),
385 n
386 )),
387 Some(&d) => self.compute_decl_const(d, e.span),
388 },
389 ExprType::Offsetof(k, aty, p) => {
390 let ty = self.compute_type_layout(aty)?;
391 let val = self.eval_offsetof(*k, aty, &ty, &p[0], &p[1..])?;
392 match k {
393 OffsetofType::Bytes => Ok((val / BITS_PER_BYTE) as i128),
394 OffsetofType::Bits => Ok(val as i128),
395 }
396 }
397 }
398 }
399
400 fn eval_offsetof(
401 &mut self,
402 k: OffsetofType,
403 aty: &'a ast::Type,
404 ty: &Type<TypeLayout>,
405 head: &'a Index,
406 rest: &'a [Index],
407 ) -> Result<u64> {
408 let (aty, ty, base) = match (&aty.variant, &ty.variant, &head.ty) {
409 (ast::TypeVariant::Record(ar), TypeVariant::Record(r), IndexType::Field(name)) => {
410 let af = match ar.fields.iter().find(|f| f.name.as_ref() == Some(name)) {
411 Some(f) => f,
412 None => {
413 return Err(anyhow!(
414 "At {}: Type has no field {}",
415 self.span(head.span),
416 name
417 ))
418 }
419 };
420 let pos = ar
421 .fields
422 .iter()
423 .position(|f| f.name.as_ref() == Some(name))
424 .unwrap();
425 let f = &r.fields[pos];
426 if f.bit_width.is_some() && k == OffsetofType::Bytes {
427 return Err(anyhow!(
428 "At {}: Cannot compute bytewise offset of bit field",
429 self.span(head.span)
430 ));
431 }
432 (&af.ty, &f.ty, f.layout.unwrap().offset_bits)
433 }
434 (ast::TypeVariant::Array(aa), TypeVariant::Array(a), IndexType::Array(pos)) => {
435 let pos = self.eval_u64_expr(pos)?;
436 match a.num_elements {
437 Some(n) if pos > n => {
438 return Err(anyhow!("At {}: Out of bounds", self.span(head.span)));
439 }
440 _ => {}
441 }
442 match a.element_type.layout.size_bits.checked_mul(pos) {
443 None => {
444 return Err(anyhow!("At {}: Offset overflow", self.span(head.span)));
445 }
446 Some(b) => (&*aa.element_type, &*a.element_type, b),
447 }
448 }
449 (ast::TypeVariant::Name(n, span), _, _) => {
450 let d = match self.declarations.get(&**n) {
451 None => {
452 return Err(anyhow!(
453 "At {}: The referenced type {} is not declared",
454 self.span(*span),
455 n
456 ))
457 }
458 Some(d) => *d,
459 };
460 self.compute_decl_ty_layout(d, head.span)?;
461 let aty = match &d.ty {
462 DeclarationType::Type(aty) => aty,
463 DeclarationType::Const(_) => unreachable!(),
464 };
465 let ty = self.type_layouts.get(n).unwrap().clone();
466 return self.eval_offsetof(k, aty, &ty, head, rest);
467 }
468 (_, _, IndexType::Field(_)) => {
469 return Err(anyhow!("At {}: Type is not a record", self.span(head.span)));
470 }
471 (_, _, IndexType::Array(_)) => {
472 return Err(anyhow!("At {}: Type is not an array", self.span(head.span)));
473 }
474 };
475 Ok(base
476 + match rest {
477 [head, rest @ ..] => self.eval_offsetof(k, aty, ty, head, rest)?,
478 _ => 0,
479 })
480 }
481
482 fn convert_array(&mut self, a: &'a ast::Array) -> Result<Array<C::Src>> {
483 Ok(Array {
484 element_type: Box::new(self.convert_type(&a.element_type)?),
485 num_elements: match &a.num_elements {
486 None => None,
487 Some(n) => Some(self.eval_u64_expr(n)?),
488 },
489 })
490 }
491}