rucc_sema/tast.rs
1//! The arenas of the typed tree, and everything that hangs off them.
2//!
3//! Design: `spec/03-architecture.md` section 3.3 and `spec/07-types-and-semantics.md` section
4//! 7.14.
5//!
6//! The same shape as the untyped tree and for the same reasons: flat vectors, four-byte
7//! indices, spans out of line, one owner per translation unit and one drop at the end of it.
8//! What is different is that a type is in the node rather than beside it, because every walk
9//! over this tree reads the type of every node it touches, which is exactly not true of spans.
10//!
11//! One [`Tast`] does not own the [`Types`](rucc_types::Types) its nodes point into. A type
12//! outlives the tree that mentions it, the two are built together and handed on together, and
13//! putting the table inside the tree would mean a pass that only wants to ask what a type is
14//! has to borrow the tree to do it.
15
16use std::fmt;
17use std::ops::Index;
18
19use rucc_base::float::Float;
20use rucc_base::{Idx, IdxRange, Symbol};
21use rucc_diag::Span;
22use rucc_lex::StringLiteral;
23use rucc_types::VlaId;
24
25use crate::asm::{Asm, AsmId, AsmOperand, AsmOperandList, LabelList, StrList};
26use crate::decl::{Decl, DeclId, DeclList, InitEntry};
27use crate::expr::{Expr, ExprId, ExprList};
28use crate::stmt::{Case, CaseId, Stmt, StmtId, StmtList};
29
30/// A folded constant, in the value table.
31pub type ConstId = Idx<Const>;
32
33/// A string literal, in the literal table.
34pub type StrId = Idx<StringLiteral>;
35
36/// A label, in the label table.
37pub type LabelId = Idx<Label>;
38
39/// The value of a constant expression, after folding.
40///
41/// Integers are held in a hundred and twenty eight bits whatever their type, which covers every
42/// integer type this compiler has including `__int128`. A `_BitInt(N)` wider than that is not
43/// representable here and is refused where it is written rather than silently truncated.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Const {
46 /// An integer, sign extended into the whole width from the type it has.
47 Int(i128),
48 /// A floating value, in the target's format rather than the host's.
49 Float(Float),
50 /// The address of an object, which is a number nobody knows until the link.
51 Address(Address),
52}
53
54/// An address constant: some object, and how far into it.
55///
56/// This is what `&x`, `a + 1` and `&s.field` fold to, and it is the reason folding hands back
57/// something richer than a number. The value is not known here and will not be known until the
58/// linker places the object, so what a static initializer needs is not the value but the pair
59/// that names it, which is what an object file's relocation records.
60///
61/// A pointer with no object behind it is not one of these. `(int *)4` folds to [`Const::Int`],
62/// because four is the whole answer and nothing has to be relocated.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub struct Address {
65 /// The object the address is into.
66 pub base: Base,
67 /// How many bytes into it, which a member or a subscript adds to and which may be outside
68 /// the object: `&a[10]` on an `int a[10]` is a valid address constant and is one past it.
69 pub offset: i128,
70}
71
72/// What an address constant is an address of.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum Base {
75 /// A declared object or function, which the linker knows by name.
76 Decl(DeclId),
77 /// A string literal, which has static storage duration and no name of its own.
78 Str(StrId),
79}
80
81/// A label, and the statement it names.
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub struct Label {
84 /// The name it was written with.
85 pub name: Symbol,
86 /// The statement it labels, absent for a label that was used and never defined, which is a
87 /// diagnostic rather than a reason to lose the reference.
88 pub stmt: Option<StmtId>,
89}
90
91/// One typed translation unit.
92#[derive(Default)]
93pub struct Tast {
94 exprs: Vec<Expr>,
95 expr_spans: Vec<Span>,
96 stmts: Vec<Stmt>,
97 stmt_spans: Vec<Span>,
98 decls: Vec<Decl>,
99 decl_spans: Vec<Span>,
100
101 consts: Vec<Const>,
102 strings: Vec<StringLiteral>,
103 labels: Vec<Label>,
104 vlas: Vec<ExprId>,
105 asms: Vec<Asm>,
106
107 expr_refs: Vec<ExprId>,
108 stmt_refs: Vec<StmtId>,
109 decl_refs: Vec<DeclId>,
110 str_refs: Vec<StrId>,
111 label_refs: Vec<LabelId>,
112 cases: Vec<Case>,
113 init_entries: Vec<InitEntry>,
114 asm_operands: Vec<AsmOperand>,
115
116 top_level: Vec<DeclId>,
117}
118
119impl Tast {
120 /// An empty tree.
121 #[must_use]
122 pub fn new() -> Tast {
123 Tast::default()
124 }
125
126 /// The objects and functions of the translation unit, in the order they were declared.
127 #[must_use]
128 pub fn top_level(&self) -> &[DeclId] {
129 &self.top_level
130 }
131
132 /// Adds a declaration at file scope.
133 pub fn add_top_level(&mut self, decl: DeclId) {
134 self.top_level.push(decl);
135 }
136
137 /// Adds an expression, with the source it came from.
138 ///
139 /// # Panics
140 ///
141 /// Panics if the arena would exceed four billion nodes, which is not a translation unit
142 /// this compiler intends to accept.
143 pub fn expr(&mut self, expr: Expr, span: Span) -> ExprId {
144 let id = Idx::from_usize(self.exprs.len());
145 self.exprs.push(expr);
146 self.expr_spans.push(span);
147 id
148 }
149
150 /// Adds a statement, with the source it came from.
151 ///
152 /// # Panics
153 ///
154 /// Panics if the arena would exceed four billion nodes.
155 pub fn stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
156 let id = Idx::from_usize(self.stmts.len());
157 self.stmts.push(stmt);
158 self.stmt_spans.push(span);
159 id
160 }
161
162 /// Adds a declaration, with the source it came from.
163 ///
164 /// # Panics
165 ///
166 /// Panics if the arena would exceed four billion nodes.
167 pub fn decl(&mut self, decl: Decl, span: Span) -> DeclId {
168 let id = Idx::from_usize(self.decls.len());
169 self.decls.push(decl);
170 self.decl_spans.push(span);
171 id
172 }
173
174 /// Replaces a declaration, which is what a definition of something already declared does.
175 ///
176 /// # Panics
177 ///
178 /// Panics if `id` is not a declaration of this tree.
179 pub fn set_decl(&mut self, id: DeclId, decl: Decl) {
180 self.decls[id.index()] = decl;
181 }
182
183 /// Replaces a statement, which is what a `switch` does to the cases in its body.
184 ///
185 /// A `case` is checked before the table it is an entry of exists, since the table is a run
186 /// and the run is not known until the whole body has been walked. So the statement is written
187 /// with a placeholder entry and given its real one here.
188 ///
189 /// # Panics
190 ///
191 /// Panics if `id` is not a statement of this tree.
192 pub fn set_stmt(&mut self, id: StmtId, stmt: Stmt) {
193 self.stmts[id.index()] = stmt;
194 }
195
196 /// The source an expression came from.
197 #[must_use]
198 pub fn expr_span(&self, id: ExprId) -> Span {
199 self.expr_spans[id.index()]
200 }
201
202 /// The source a statement came from.
203 #[must_use]
204 pub fn stmt_span(&self, id: StmtId) -> Span {
205 self.stmt_spans[id.index()]
206 }
207
208 /// The source a declaration came from.
209 #[must_use]
210 pub fn decl_span(&self, id: DeclId) -> Span {
211 self.decl_spans[id.index()]
212 }
213
214 /// Records the size of one variable length array, and gives back its identity.
215 ///
216 /// The type table keeps a [`VlaId`] and nothing else, because two variable length arrays
217 /// written with the same element type are still distinct types and interning them together
218 /// would say they are not. The expression itself lives here, since it is evaluated once
219 /// where the declaration is reached and its value is what every `sizeof` of that type
220 /// afterwards answers with.
221 ///
222 /// # Panics
223 ///
224 /// Panics if the table would exceed four billion entries.
225 pub fn add_vla(&mut self, size: ExprId) -> VlaId {
226 let id = u32::try_from(self.vlas.len()).expect("too many variable length arrays");
227 self.vlas.push(size);
228 VlaId(id)
229 }
230
231 /// The size expression of one variable length array.
232 ///
233 /// # Panics
234 ///
235 /// Panics if `id` is not one of this tree's.
236 #[must_use]
237 pub fn vla_size(&self, id: VlaId) -> ExprId {
238 self.vlas[id.0 as usize]
239 }
240
241 /// Records that a label names a statement, which is not known when the label is created
242 /// because a `goto` may come first.
243 ///
244 /// # Panics
245 ///
246 /// Panics if `id` is not a label of this tree.
247 pub fn define_label(&mut self, id: LabelId, stmt: StmtId) {
248 self.labels[id.index()].stmt = Some(stmt);
249 }
250
251 /// How many expressions, statements and declarations the tree holds.
252 #[must_use]
253 pub fn counts(&self) -> Counts {
254 Counts { exprs: self.exprs.len(), stmts: self.stmts.len(), decls: self.decls.len() }
255 }
256
257 /// Whether nothing has been checked into this tree.
258 #[must_use]
259 pub fn is_empty(&self) -> bool {
260 self.exprs.is_empty() && self.stmts.is_empty() && self.decls.is_empty()
261 }
262}
263
264/// How many nodes of each kind a typed tree holds.
265#[derive(Debug, Clone, Copy, PartialEq, Eq)]
266pub struct Counts {
267 /// Expressions.
268 pub exprs: usize,
269 /// Statements.
270 pub stmts: usize,
271 /// Declarations.
272 pub decls: usize,
273}
274
275impl fmt::Debug for Tast {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 // The same reasoning as the untyped tree: nobody wants a translation unit as a `{:?}`,
278 // and the thing they did want has a printer.
279 let counts = self.counts();
280 f.debug_struct("Tast")
281 .field("exprs", &counts.exprs)
282 .field("stmts", &counts.stmts)
283 .field("decls", &counts.decls)
284 .field("top_level", &self.top_level.len())
285 .finish()
286 }
287}
288
289/// Generates the read side of a table that holds one item per index.
290macro_rules! node_table {
291 ($id:ty => $item:ty, $field:ident) => {
292 impl Index<$id> for Tast {
293 type Output = $item;
294
295 #[inline]
296 fn index(&self, id: $id) -> &$item {
297 &self.$field[id.index()]
298 }
299 }
300 };
301}
302
303/// Generates both sides of a side table whose items are added one at a time.
304macro_rules! side_table {
305 (
306 $(#[$doc:meta])*
307 $add:ident, $id:ty => $item:ty, $field:ident
308 ) => {
309 impl Tast {
310 $(#[$doc])*
311 ///
312 /// # Panics
313 ///
314 /// Panics if the table would exceed four billion entries.
315 pub fn $add(&mut self, item: $item) -> $id {
316 let id = Idx::from_usize(self.$field.len());
317 self.$field.push(item);
318 id
319 }
320 }
321
322 node_table!($id => $item, $field);
323 };
324}
325
326/// Generates both sides of a table that is read in runs.
327macro_rules! list_table {
328 (
329 $(#[$doc:meta])*
330 $add:ident, $list:ty => $item:ty, $field:ident
331 ) => {
332 impl Tast {
333 $(#[$doc])*
334 ///
335 /// # Panics
336 ///
337 /// Panics if the table would exceed four billion entries.
338 pub fn $add(&mut self, items: &[$item]) -> $list {
339 let start = Idx::from_usize(self.$field.len());
340 self.$field.extend_from_slice(items);
341 let end = Idx::from_usize(self.$field.len());
342 IdxRange::new(start, end)
343 }
344 }
345
346 impl Index<$list> for Tast {
347 type Output = [$item];
348
349 #[inline]
350 fn index(&self, list: $list) -> &[$item] {
351 &self.$field[list.as_usize_range()]
352 }
353 }
354 };
355}
356
357node_table!(ExprId => Expr, exprs);
358node_table!(StmtId => Stmt, stmts);
359node_table!(DeclId => Decl, decls);
360node_table!(CaseId => Case, cases);
361
362side_table! {
363 /// Adds a folded constant.
364 add_const, ConstId => Const, consts
365}
366side_table! {
367 /// Adds a string literal.
368 add_string, StrId => StringLiteral, strings
369}
370side_table! {
371 /// Adds a label, which is not defined until the statement it names has been seen.
372 add_label, LabelId => Label, labels
373}
374side_table! {
375 /// Adds an assembly statement.
376 add_asm, AsmId => Asm, asms
377}
378
379list_table! {
380 /// Adds a run of expression references, which is what a call's arguments are.
381 add_expr_refs, ExprList => ExprId, expr_refs
382}
383list_table! {
384 /// Adds a run of statement references, which is what a block is.
385 add_stmt_refs, StmtList => StmtId, stmt_refs
386}
387list_table! {
388 /// Adds a run of declaration references, which is what a declaration statement is.
389 add_decl_refs, DeclList => DeclId, decl_refs
390}
391list_table! {
392 /// Adds a run of string literal references, which is what an `asm` clobber list is.
393 add_str_refs, StrList => StrId, str_refs
394}
395list_table! {
396 /// Adds a run of label references, which is what the labels of an `asm goto` are.
397 add_label_refs, LabelList => LabelId, label_refs
398}
399list_table! {
400 /// Adds the operands of one section of an `asm` statement.
401 add_asm_operands, AsmOperandList => AsmOperand, asm_operands
402}
403list_table! {
404 /// Adds the cases of one `switch`, in the order a jump table wants them.
405 add_cases, crate::stmt::CaseList => Case, cases
406}
407list_table! {
408 /// Adds the values one initializer stores.
409 add_init_entries, crate::decl::InitList => InitEntry, init_entries
410}
411
412#[cfg(test)]
413mod tests {
414 use rucc_ast::BinaryOp;
415 use rucc_types::{IntKind, Types};
416
417 use super::*;
418 use crate::decl::{DeclKind, Definition, Linkage, StorageDuration};
419 use crate::expr::{Category, Conversion, ExprKind};
420
421 /// The sizes are asserted rather than left to whoever adds the next variant.
422 ///
423 /// A node that grows costs the whole arena, and the day one does is a day somebody should
424 /// have to say so out loud rather than a day the walk over a large translation unit gets
425 /// slower for no reason anybody can point at.
426 ///
427 /// A case is the outlier at forty eight bytes, because two `i128` bounds want sixteen byte
428 /// alignment and nothing smaller holds a `switch` over `__int128`. It buys its size back by
429 /// being rare: one entry per `case` rather than one per node.
430 ///
431 /// A declaration went from thirty six bytes to forty four when it was given the parameter
432 /// list of a function definition, which is a field only a definition fills in and every
433 /// declaration pays for. The alternative was a side table keyed by declaration, and it was
434 /// not taken: a lookup per function in a table that is empty for almost every entry is
435 /// worse than eight bytes on a node there are far fewer of than there are expressions.
436 #[test]
437 fn the_nodes_are_the_size_they_are_meant_to_be() {
438 assert_eq!(size_of::<Expr>(), 24);
439 assert_eq!(size_of::<Stmt>(), 24);
440 assert_eq!(size_of::<Decl>(), 44);
441 assert_eq!(size_of::<Case>(), 48);
442 }
443
444 #[test]
445 fn a_tree_hands_back_what_was_put_into_it() {
446 let types = Types::new();
447 let int = types.int(IntKind::Int);
448 let mut tast = Tast::new();
449
450 let one = tast.add_const(Const::Int(1));
451 let left = tast.expr(Expr::new(ExprKind::Const(one), int, Category::Rvalue), Span::DUMMY);
452 let right = tast.expr(Expr::new(ExprKind::Const(one), int, Category::Rvalue), Span::DUMMY);
453 let sum = Expr::new(
454 ExprKind::Binary { op: BinaryOp::Add, lhs: left, rhs: right },
455 int,
456 Category::Rvalue,
457 );
458 let sum = tast.expr(sum, Span::new(0, 5));
459
460 assert_eq!(tast[left].ty, int);
461 assert_eq!(tast[sum].category, Category::Rvalue);
462 assert_eq!(tast.expr_span(sum), Span::new(0, 5));
463 assert_eq!(tast.counts().exprs, 3);
464 assert_eq!(tast[one], Const::Int(1));
465 }
466
467 #[test]
468 fn a_conversion_is_a_node_and_not_a_difference_between_two_types() {
469 let types = Types::new();
470 let char_type = types.int(IntKind::Char);
471 let int = types.int(IntKind::Int);
472 let mut tast = Tast::new();
473
474 let object = tast.decl(
475 Decl {
476 name: None,
477 ty: char_type,
478 kind: DeclKind::Object,
479 linkage: Linkage::None,
480 duration: StorageDuration::Automatic,
481 state: Definition::Defined,
482 alignment: None,
483 init: None,
484 params: DeclList::EMPTY,
485 body: None,
486 },
487 Span::DUMMY,
488 );
489 let name =
490 tast.expr(Expr::new(ExprKind::Decl(object), char_type, Category::Lvalue), Span::DUMMY);
491 let read = tast.expr(
492 Expr::new(
493 ExprKind::Convert { kind: Conversion::Lvalue, operand: name },
494 char_type,
495 Category::Rvalue,
496 ),
497 Span::DUMMY,
498 );
499 let promoted = tast.expr(
500 Expr::new(
501 ExprKind::Convert { kind: Conversion::Arithmetic, operand: read },
502 int,
503 Category::Rvalue,
504 ),
505 Span::DUMMY,
506 );
507
508 // Nothing downstream has to work out that a `char` met an `int` somewhere: the two
509 // steps that got it there are in the tree, in the order they happened.
510 assert_eq!(tast[promoted].ty, int);
511 let ExprKind::Convert { kind, operand } = tast[promoted].kind else { panic!("a convert") };
512 assert_eq!(kind, Conversion::Arithmetic);
513 assert_eq!(tast[operand].ty, char_type);
514 }
515
516 #[test]
517 fn a_run_comes_back_as_a_slice() {
518 let types = Types::new();
519 let int = types.int(IntKind::Int);
520 let mut tast = Tast::new();
521
522 let zero = tast.add_const(Const::Int(0));
523 let args: Vec<ExprId> = (0..3)
524 .map(|_| {
525 tast.expr(Expr::new(ExprKind::Const(zero), int, Category::Rvalue), Span::DUMMY)
526 })
527 .collect();
528 let list = tast.add_expr_refs(&args);
529
530 assert_eq!(&tast[list], args.as_slice());
531 }
532
533 #[test]
534 fn a_label_is_made_before_it_is_defined_because_a_goto_may_come_first() {
535 let mut tast = Tast::new();
536 let mut names = rucc_base::Interner::new();
537 let name = names.intern("done");
538
539 let label = tast.add_label(Label { name, stmt: None });
540 let jump = tast.stmt(Stmt::Goto(label), Span::DUMMY);
541 let target = tast.stmt(Stmt::Empty, Span::DUMMY);
542 tast.define_label(label, target);
543
544 assert_eq!(tast[jump], Stmt::Goto(label));
545 assert_eq!(tast[label].stmt, Some(target));
546 }
547}