Skip to main content

rucc_lower/
unit.rs

1//! The module level of the walk: what a translation unit's declarations become.
2//!
3//! Design: `spec/08-ir.md` section 8.9.
4//!
5//! One typed tree becomes one [`Module`]. A file-scope object becomes a global with an image
6//! built from its initializer, a function becomes a [`Func`] whose body is built by
7//! [`body`](mod@crate::body), and a string literal becomes an unnamed constant global that
8//! whatever mentioned it points at.
9//!
10//! # What an image is
11//!
12//! An initializer arrives here already flattened: one entry per scalar that is stored, each
13//! with the byte offset it goes at, with every designator and every nested brace already
14//! resolved. So building the image is a walk over the entries in offset order, filling the gaps
15//! between them with zeros, and the only thing that has to be worked out per entry is whether
16//! the value is a number, a run of bytes from a string literal, or the address of something the
17//! linker has to place.
18//!
19//! # Names
20//!
21//! An object with linkage is known by the name it was written with, and there is nothing to
22//! invent. A `static` inside a function has no linkage and still needs a name in the object
23//! file, so it gets `name.N`, which is what gcc does and is why two functions may each have a
24//! `static int count;` without colliding. A string literal has no name at all and gets
25//! `.Lstr.N`, whose leading dot keeps it out of the symbol table on every target that has the
26//! convention.
27
28use std::cmp::Ordering;
29use std::collections::{BTreeMap, HashMap, HashSet};
30
31use rucc_base::{Interner, Symbol};
32use rucc_diag::{Diagnostic, Span};
33use rucc_ir::{
34    DataList, Datum, Func, Global, Imm, Linkage as IrLinkage, Module, Reloc, TlsModel, Type,
35};
36use rucc_sema::{
37    Base, Const, Conversion, DeclId, DeclKind, Definition, Eval, ExprId, ExprKind, InitEntry,
38    InitList, Linkage, StorageDuration, StrId, Tast,
39};
40use rucc_target::TargetInfo;
41use rucc_types::{TypeId, TypeKind, Types, compatible};
42
43use crate::abi::{self, Plan};
44use crate::body;
45use crate::reach;
46use crate::repr;
47
48/// Everything the walk reads, which is a checked translation unit and the target it is for.
49///
50/// The interner is mutable because the walk invents names the program never wrote: the label a
51/// string literal is emitted under, and the mangled name of a function-scope `static`.
52#[derive(Debug)]
53pub struct Context<'a> {
54    /// The typed tree.
55    pub tast: &'a Tast,
56    /// The types it points into.
57    pub types: &'a Types,
58    /// What is being compiled for, which is where every width and every alignment comes from.
59    pub target: &'a TargetInfo,
60    /// The name table.
61    pub names: &'a mut Interner,
62}
63
64/// What the walk produced.
65#[derive(Debug)]
66pub struct Lowered {
67    /// The module, which is complete even when something was reported: a construct that is not
68    /// supported yet leaves the rest of the function around it intact.
69    pub module: Module,
70    /// What was reported, in the order it was found.
71    pub diagnostics: Vec<Diagnostic>,
72}
73
74/// Walks a checked translation unit and builds the IR for it.
75///
76/// `name` is the module's name, which is the file the tree came from.
77#[must_use]
78pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
79    let Context { tast, types, target, names } = cx;
80    let module = Module::new(names.intern(name), target);
81    let mut unit = Unit {
82        tast,
83        types,
84        target,
85        names,
86        module,
87        diagnostics: Vec::new(),
88        strings: HashMap::new(),
89        statics: HashMap::new(),
90        done: HashSet::new(),
91        reachable: reach::reachable(tast),
92    };
93    unit.run();
94    Lowered { module: unit.module, diagnostics: unit.diagnostics }
95}
96
97/// The walk over one translation unit, and everything it has built so far.
98pub(crate) struct Unit<'a> {
99    pub(crate) tast: &'a Tast,
100    pub(crate) types: &'a Types,
101    pub(crate) target: &'a TargetInfo,
102    pub(crate) names: &'a mut Interner,
103    pub(crate) module: Module,
104    pub(crate) diagnostics: Vec<Diagnostic>,
105    /// The global each string literal was emitted as, so that two mentions of one literal are
106    /// one object.
107    strings: HashMap<StrId, Symbol>,
108    /// The name each object with no linkage was given.
109    statics: HashMap<DeclId, Symbol>,
110    /// What has been emitted, because a redeclaration is the same declaration seen twice.
111    done: HashSet<DeclId>,
112    /// What something in the file reaches, which is what decides whether a function with
113    /// internal linkage is emitted at all.
114    reachable: HashSet<DeclId>,
115}
116
117// The debug is by hand and short: a translation unit is not something anybody wants printed as
118// a `{:?}`, and the module has a printer of its own for when they do.
119impl std::fmt::Debug for Unit<'_> {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        f.debug_struct("Unit")
122            .field("module", &self.module.counts())
123            .field("diagnostics", &self.diagnostics.len())
124            .finish()
125    }
126}
127
128impl Unit<'_> {
129    /// Every declaration the file made, in the order it made them.
130    fn run(&mut self) {
131        for index in 0..self.tast.top_level().len() {
132            let decl = self.tast.top_level()[index];
133            if !self.done.insert(decl) {
134                continue;
135            }
136            match self.tast[decl].kind {
137                DeclKind::Function => self.function(decl),
138                DeclKind::Object => self.object(decl),
139            }
140        }
141    }
142
143    /// One object with static storage duration.
144    fn object(&mut self, decl: DeclId) {
145        let tast = self.tast;
146        let node = &tast[decl];
147        let (ty, state, init) = (node.ty, node.state, node.init);
148        let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
149        let span = tast.decl_span(decl);
150        if duration == StorageDuration::Automatic {
151            // A block-scope object with automatic storage is a slot or a value in the function
152            // that declares it, and the body is what makes it. Nothing is emitted here.
153            return;
154        }
155
156        let symbol = self.symbol_of(decl);
157        let size = repr::size_of(self.types, self.target, ty);
158        let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
159        let mut global = Global::new(symbol, size, align);
160        global.linkage = match linkage {
161            Linkage::External => IrLinkage::External,
162            Linkage::Internal | Linkage::None => IrLinkage::Internal,
163        };
164        global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
165        global.constant = repr::is_read_only(self.types, ty);
166        global.init = match state {
167            // `extern int x;` and nothing else names an object another translation unit
168            // defines. The global is here so that a reference to it has something to resolve
169            // against, and it has no image, which is what makes it a declaration.
170            Definition::Declared => None,
171            Definition::Tentative => Some(self.zeros(size)),
172            Definition::Defined => {
173                let (data, covered) = self.image(init, size, span);
174                // The object is as large as its image when the image is the larger of the two.
175                // A structure whose last member is a flexible array is the only way that
176                // happens: `sizeof` answers without the array and an initializer that fills it
177                // makes an object big enough to hold what was written. C 6.7.2.1p18 leaves the
178                // size to the implementation, gcc grows the object, and this does the same
179                // rather than hand the linker a size the image does not fit in.
180                global.size = size.max(covered);
181                Some(data)
182            }
183        };
184        self.module.add_global(global);
185    }
186
187    /// One function, with its body when it has one.
188    fn function(&mut self, decl: DeclId) {
189        if self.is_dropped(decl) {
190            return;
191        }
192        let tast = self.tast;
193        let node = &tast[decl];
194        let (ty, linkage, body, align) = (node.ty, node.linkage, node.body, node.alignment);
195        let span = tast.decl_span(decl);
196        let Some(name) = node.name else { return };
197        let name = self.library_name(name).unwrap_or(name);
198        let Some(plan) = self.plan(ty, &[], span) else { return };
199
200        let mut func = Func::new(name, plan.signature.clone());
201        func.align = align;
202        func.linkage = match linkage {
203            Linkage::Internal | Linkage::None => IrLinkage::Internal,
204            Linkage::External => IrLinkage::External,
205        };
206        if body.is_some() {
207            body::lower(self, decl, &mut func, &plan);
208        }
209        self.module.add_func(func);
210    }
211
212    /// Whether this function is one nothing can call, which is the set that is not emitted.
213    ///
214    /// A name with internal linkage is not visible to another translation unit, so a definition
215    /// of one that nothing here refers to is a definition of something that can never run.
216    /// [`reach`](mod@crate::reach) is what worked out which those are, and an attribute that asks
217    /// for the definition to be kept has already been read into the answer.
218    ///
219    /// Nothing is said about it. gcc has `-Wunused-function` for a `static` function nobody
220    /// wrote a call to, which is a warning about the program, and this is not that: the header
221    /// that defines six of them is not the file being compiled and its author is not the person
222    /// reading the output.
223    fn is_dropped(&self, decl: DeclId) -> bool {
224        self.tast[decl].linkage != Linkage::External && !self.reachable.contains(&decl)
225    }
226
227    /// How everything a call to this function type hands over travels, and [`None`] for one the
228    /// walk cannot make.
229    ///
230    /// `actual` is the types of the arguments at a call site, which matter only past the end of
231    /// the prototype: what a variadic argument does is decided from what was written there, and
232    /// there is no parameter to decide it from. A definition passes nothing for it.
233    pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
234        self.plan_with(ty, actual, false, span)
235    }
236
237    /// The same, as the call site sees it rather than as the function does.
238    ///
239    /// The two differ for a type that is not a prototype. An old style definition is the one of
240    /// those that knows what its parameters are, and 6.5.2.2p6 checks a call against a prototype
241    /// and against nothing at all otherwise, so a parameter it disagrees with does not make the
242    /// call wrong and cannot be what the argument travels as either: the value at the call is
243    /// the argument's own type and nothing converted it. So a parameter the argument facing it
244    /// is compatible with is used, which is the usual case and is what makes the call go to the
245    /// name, and one it is not compatible with gives way to what was actually written. A call
246    /// like that is undefined behaviour if control reaches it and the file still has to
247    /// translate, which is the same position [`Body::direct`](crate::body) already takes.
248    pub(crate) fn call_plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
249        self.plan_with(ty, actual, true, span)
250    }
251
252    fn plan_with(
253        &mut self,
254        ty: TypeId,
255        actual: &[TypeId],
256        at_call: bool,
257        span: Span,
258    ) -> Option<Plan> {
259        let canonical = self.types.canonical(ty);
260        let canonical = match self.types.kind(canonical) {
261            // A call goes through a pointer to a function, and the type in hand may be either.
262            TypeKind::Pointer(pointee) => self.types.canonical(pointee),
263            _ => canonical,
264        };
265        let TypeKind::Function(id) = self.types.kind(canonical) else {
266            self.unsupported("a call through something that is not a function", span);
267            return None;
268        };
269        let signature = self.types.signature(id);
270        let ret = signature.ret;
271        // A function declared without a prototype takes what it is given, which is what a
272        // signature with no parameters and no end to them says. C23 removed these and this is
273        // what `int f();` means in every dialect before it.
274        let variadic = signature.variadic || !signature.prototyped;
275        let params = if at_call && !signature.prototyped {
276            // An argument past the end of the list has no parameter to travel as, which is what
277            // a call to an unprototyped function with more arguments than the definition takes
278            // is, so the list ends where the arguments do.
279            signature
280                .params
281                .iter()
282                .zip(actual)
283                .map(|(&param, &arg)| if compatible(self.types, param, arg) { param } else { arg })
284                .collect()
285        } else {
286            signature.params.clone()
287        };
288
289        match abi::plan(self.types, self.target, ret, &params, actual, variadic) {
290            Ok(plan) => Some(plan),
291            Err(what) => {
292                self.unsupported(what, span);
293                None
294            }
295        }
296    }
297
298    /// The image of an initializer: the entries in ascending order, with the gaps zeroed, and
299    /// how many bytes it covers.
300    ///
301    /// The count is the size that was asked for except when a flexible array member was given
302    /// something to hold, which is the one case where an image is larger than the type it is an
303    /// image of.
304    pub(crate) fn image(
305        &mut self,
306        init: Option<InitList>,
307        size: u64,
308        span: Span,
309    ) -> (DataList, u64) {
310        let Some(init) = init else { return (self.zeros(size), size) };
311        let (data, at) = self.pieces(init, size, span);
312        (self.module.push_data(&data), at)
313    }
314
315    /// The data an image is made of, before it becomes a [`DataList`].
316    ///
317    /// This is apart from [`Self::image`] so that an image can be built inside another one,
318    /// which is what a compound literal used as a value in an initializer needs.
319    fn pieces(&mut self, init: InitList, size: u64, span: Span) -> (Vec<Datum>, u64) {
320        let entries = self.in_image_order(&self.tast[init]);
321        let mut packed = self.packed(&entries, size);
322        let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
323        let mut at = 0;
324        for entry in entries {
325            let piece = self.entry(entry, &mut packed, size);
326            if piece.is_empty() {
327                continue;
328            }
329            let covered: u64 = piece.iter().map(|datum| datum.size(&self.module)).sum();
330            match entry.offset.cmp(&at) {
331                Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
332                // An entry that begins inside the one before it, which is neither the same
333                // place nor a later one. A union whose members are initialized through two
334                // designators is the way to write it. The earlier bytes are already in the
335                // list and the image cannot take them out again, so this is refused, and
336                // nothing here is wrong enough to drop the rest of the image.
337                Ordering::Less => {
338                    self.unsupported("an initializer that writes over an earlier one", span);
339                    continue;
340                }
341                Ordering::Equal => {}
342            }
343            at = entry.offset + covered;
344            data.extend(piece);
345        }
346        if at < size {
347            // The tail of a partly initialized object, which C says is zero. So is the tail of
348            // an array the initializer did not fill, and so is every byte of padding.
349            data.push(Datum::Zero(size - at));
350            at = size;
351        }
352        (data, at)
353    }
354
355    /// The entries an image is written from, which is not the order they were written in.
356    ///
357    /// A designator names a place, and the places may be named in any order at all:
358    /// `{ .b = 2, .a = 1 }` is the same object as `{ .a = 1, .b = 2 }` and C says so in as many
359    /// words. An image is bytes in ascending order, so the entries are put in that order here.
360    /// The sort is stable, which is what makes the rest of the rule work: naming one place
361    /// twice is legal and the last of them is the one that stands, so among the entries at one
362    /// offset the written order is kept and all but the last are dropped.
363    ///
364    /// A bit-field is never dropped, because several of them share one offset without writing
365    /// over anything. Which bytes they came to is settled by [`Self::packed`] before this runs
366    /// and the whole run goes in under the first entry that has a bit in it.
367    fn in_image_order(&self, entries: &[InitEntry]) -> Vec<InitEntry> {
368        let mut sorted = entries.to_vec();
369        sorted.sort_by_key(|entry| entry.offset);
370        let mut kept: Vec<InitEntry> = Vec::with_capacity(sorted.len());
371        for entry in sorted {
372            if !entry.is_bit_field() {
373                let over = |last: &InitEntry| last.offset == entry.offset && !last.is_bit_field();
374                while kept.last().is_some_and(over) {
375                    kept.pop();
376                }
377            }
378            kept.push(entry);
379        }
380        kept
381    }
382
383    /// What one entry of an initializer puts in the image.
384    ///
385    /// A bit-field is not a datum of its own, because two of them can live in one byte and an
386    /// image is written in bytes. They were put together into their bytes by [`Self::packed`]
387    /// before this ran, and the whole run of bytes goes in under the first entry that has a
388    /// bit in it, which is why a later one in the same run answers with nothing.
389    ///
390    /// An entry is usually one datum and a compound literal read is the reason the answer is a
391    /// list: that entry is a whole object and puts as many data in as the object it is.
392    fn entry(&mut self, entry: InitEntry, packed: &mut BTreeMap<u64, u8>, size: u64) -> Vec<Datum> {
393        if entry.is_bit_field() {
394            let Some(bytes) = take_run(packed, entry.offset) else { return Vec::new() };
395            return vec![Datum::Bytes(self.module.push_bytes(&bytes))];
396        }
397        if let Some(literal) = self.literal_read(entry.value) {
398            return self.literal_image(literal, self.tast.expr_span(entry.value));
399        }
400        // How much room is left in the object, which is what a string literal longer than the
401        // array it initializes is cut down to. An entry that begins where the object ends is the
402        // initializer of a flexible array member, and there the object grows to hold what was
403        // written rather than the value being cut to fit, so nothing is taken off it.
404        let room = if entry.offset < size { size - entry.offset } else { u64::MAX };
405        self.datum(entry.value, room).into_iter().collect()
406    }
407
408    /// The compound literal an entry reads, if that is what the entry is.
409    ///
410    /// Reading an object is a node of its own, so a literal used as a value comes through as a
411    /// read of a literal. A literal whose address is taken is not a read and is not this: that
412    /// one folds to an address and goes in as a relocation, with the object it points at emitted
413    /// on its own.
414    fn literal_read(&self, value: ExprId) -> Option<DeclId> {
415        let ExprKind::Convert { kind: Conversion::Lvalue, operand } = self.tast[value].kind else {
416            return None;
417        };
418        match self.tast[operand].kind {
419            ExprKind::CompoundLiteral(decl) => Some(decl),
420            _ => None,
421        }
422    }
423
424    /// The bytes a compound literal contributes where it is read, which are its own image.
425    ///
426    /// The literal has static storage duration here, since a file-scope initializer is the only
427    /// place this is reached from, and C 6.7.11p4 is what lets it stand as a constant element.
428    /// Its own initializer is built at the offset the entry is at, so the parent image ends up
429    /// with the literal's bytes laid into it rather than a name pointing at a second object.
430    fn literal_image(&mut self, literal: DeclId, span: Span) -> Vec<Datum> {
431        let size = repr::size_of(self.types, self.target, self.tast[literal].ty);
432        let Some(init) = self.tast[literal].init else {
433            return if size == 0 { Vec::new() } else { vec![Datum::Zero(size)] };
434        };
435        self.pieces(init, size, span).0
436    }
437
438    /// The bit-fields of an initializer, put together into the bytes they lie in.
439    ///
440    /// Only the bytes something was stored in are in the map. A field whose value is zero
441    /// leaves nothing behind, which is right: what an image does not say is zero anyway. A
442    /// field named twice takes only the bits of the field, so the last of them stands and does
443    /// not read as the two values together.
444    fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
445        let mut bytes = BTreeMap::new();
446        for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
447            let Some(folded) = self.fold(entry.value) else { continue };
448            let Const::Int(number) = folded else {
449                let span = self.tast.expr_span(entry.value);
450                let what = "a bit-field initialized by something that is not an integer";
451                self.unsupported(what, span);
452                continue;
453            };
454            let width = entry.bit_width;
455            let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
456            let mut mask = ones << entry.bit_offset;
457            let mut placed = ((number as u128) & ones) << entry.bit_offset;
458            let mut at = entry.offset;
459            while mask != 0 && at < size {
460                let (bits, keep) = ((placed & 0xff) as u8, !((mask & 0xff) as u8));
461                if bits != 0 || bytes.contains_key(&at) {
462                    let byte = bytes.entry(at).or_insert(0);
463                    *byte = (*byte & keep) | bits;
464                }
465                mask >>= 8;
466                placed >>= 8;
467                at += 1;
468            }
469        }
470        bytes
471    }
472
473    /// One entry of an image, given how many bytes are left in the object it goes in.
474    fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
475        let tast = self.tast;
476        let ty = tast[value].ty;
477        let span = tast.expr_span(value);
478        if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
479            // An array in an initializer is a string literal initializing it, because that is
480            // the only way an array is ever a value. `char s[2] = "hi";` drops the terminator,
481            // which is the one case where the literal is longer than what it initializes, and
482            // the front end has already given the value the type of the array it is filling, so
483            // the type is what says how many of the literal's bytes are part of it. `room` is
484            // still consulted because a flexible array member is filled by a literal that keeps
485            // its own type and there is no size in the object for it to be cut to.
486            let ExprKind::Str(id) = tast[value].kind else {
487                self.unsupported("this initializer", span);
488                return None;
489            };
490            let bytes = tast[id].bytes(self.target);
491            let holds = repr::size_of(self.types, self.target, ty);
492            let take = bytes.len().min(cap(holds)).min(cap(room));
493            return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
494        }
495
496        let size = repr::size_of(self.types, self.target, ty);
497        match self.fold(value)? {
498            Const::Int(number) => {
499                let ty = repr::value_type(self.types, self.target, ty)?;
500                // An integer constant of pointer type is a null pointer constant, which is what
501                // `NULL` is, or an address the program wrote as a number. An image is bytes and
502                // `ptr` says nothing about how many, so it goes in as the integer it is at the
503                // width the target's addresses have. An address the linker has to fill in is
504                // the arm below, and is the only one that stays a pointer.
505                let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
506                let imm = self.module.add_imm(Imm::int(number, ty));
507                Some(Datum::Scalar { ty, value: imm })
508            }
509            Const::Float(number) => {
510                let ty = repr::value_type(self.types, self.target, ty)?;
511                let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
512                Some(Datum::Scalar { ty, value: imm })
513            }
514            Const::Address(address) => {
515                let symbol = match address.base {
516                    Base::Decl(decl) => {
517                        // A compound literal is an object nothing declares, so the address of
518                        // one is also the only thing that asks for it to be emitted. Without
519                        // this the image names a symbol the module never defines and the link
520                        // is what finds out. Anything with a name of its own is left alone,
521                        // since the walk over the unit reaches those on its own.
522                        if self.tast[decl].name.is_none() {
523                            self.local_static(decl);
524                        }
525                        self.symbol_of(decl)
526                    }
527                    Base::Str(id) => self.string(id),
528                };
529                let addend = i64::try_from(address.offset).unwrap_or(0);
530                let size = u32::try_from(size).unwrap_or(0);
531                Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
532            }
533        }
534    }
535
536    /// An image of nothing but zeros, which is what a tentative definition has.
537    fn zeros(&mut self, size: u64) -> DataList {
538        if size == 0 {
539            return DataList::EMPTY;
540        }
541        self.module.push_data(&[Datum::Zero(size)])
542    }
543
544    /// The global a string literal is emitted as, making it the first time it is asked for.
545    pub(crate) fn string(&mut self, id: StrId) -> Symbol {
546        if let Some(&symbol) = self.strings.get(&id) {
547            return symbol;
548        }
549        let literal = &self.tast[id];
550        let bytes = literal.bytes(self.target);
551        let align = literal.encoding.element_width(self.target) / 8;
552        let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
553
554        let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
555        global.linkage = IrLinkage::Internal;
556        // Not because the type says so, since a literal is an array of `char` and not of
557        // `const char`, but because writing to one is undefined and every target puts them
558        // somewhere read-only.
559        global.constant = true;
560        let range = self.module.push_bytes(&bytes);
561        global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
562        self.module.add_global(global);
563        self.strings.insert(id, symbol);
564        symbol
565    }
566
567    /// The name the C library gives a function the program named with the `__builtin_` prefix,
568    /// and nothing for every other name.
569    ///
570    /// `__builtin_abort` is a call to `abort`: the prefix is how a program reaches the function
571    /// the library promises where a macro or a definition of its own has taken the plain name,
572    /// so the two spellings are one function and the one the linker will look for is the short
573    /// one. Which names those are is [`rucc_sema::library_name`]'s to say, since it is the same
574    /// answer the front end declared them out of.
575    fn library_name(&mut self, name: Symbol) -> Option<Symbol> {
576        let library = rucc_sema::library_name(self.names.resolve(name))?;
577        Some(self.names.intern(library))
578    }
579
580    /// The name an object or a function is known by in the object file.
581    pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
582        let tast = self.tast;
583        let node = &tast[decl];
584        if node.linkage != Linkage::None {
585            let Some(name) = node.name else { return self.names.intern(".Lanon") };
586            return self.library_name(name).unwrap_or(name);
587        }
588        if let Some(&symbol) = self.statics.get(&decl) {
589            return symbol;
590        }
591        // A `static` in a function, or a compound literal with static storage duration. The
592        // number is what makes two of them in two functions two objects.
593        let base = match node.name {
594            Some(name) => self.names.resolve(name).to_string(),
595            None => ".Lanon".to_string(),
596        };
597        let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
598        self.statics.insert(decl, symbol);
599        symbol
600    }
601
602    /// Emits the global for an object with static storage duration declared inside a function.
603    pub(crate) fn local_static(&mut self, decl: DeclId) {
604        if !self.done.insert(decl) {
605            return;
606        }
607        match self.tast[decl].kind {
608            // A function declared inside a body is a declaration of the function, not an
609            // object with static storage that happens to be one.
610            DeclKind::Function => self.function(decl),
611            DeclKind::Object => self.object(decl),
612        }
613    }
614
615    /// The value of a constant expression, reporting what folding it reported.
616    fn fold(&mut self, expr: ExprId) -> Option<Const> {
617        let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
618        let folded = eval.constant(expr);
619        let reported = eval.finish();
620        self.diagnostics.extend(reported);
621        match folded {
622            Ok(value) => Some(value),
623            Err(stop) => {
624                if !stop.poisoned {
625                    let span = self.tast.expr_span(stop.at);
626                    self.unsupported("an initializer this compiler cannot fold", span);
627                }
628                None
629            }
630        }
631    }
632
633    /// Reports a construct the walk does not build IR for yet.
634    pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
635        self.diagnostics.push(
636            Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
637        );
638    }
639
640    /// Reports a call to a builtin this compiler knows the name of and does nothing with.
641    ///
642    /// It is its own message rather than [`Self::unsupported`] because the construct is not the
643    /// problem: a call is a call, and what is missing is the one function it goes to. The note is
644    /// what a reader needs, since a builtin is the one name a programmer does not expect to have
645    /// to provide and the alternative to this message is a linker asking them for it.
646    pub(crate) fn missing_builtin(&mut self, spelled: &str, span: Span) {
647        let message = format!("`{spelled}` is not implemented yet");
648        let note = "a call to it would go to a symbol no object file defines, so this is refused \
649                    here rather than at the link";
650        self.diagnostics.push(Diagnostic::error(message, span).with_code("E0686").note(note, span));
651    }
652}
653
654/// A count of bytes as a length of a slice of them, saturating on a target whose addresses are
655/// wider than this host's.
656fn cap(bytes: u64) -> usize {
657    usize::try_from(bytes).unwrap_or(usize::MAX)
658}
659
660/// The run of bytes a bit-field entry starts, taken out of the map.
661///
662/// [`None`] when there is no byte at that offset, which means either that every bit-field in
663/// it was initialized to zero or that an earlier entry in the same run already took it.
664fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
665    let mut run = vec![bytes.remove(&start)?];
666    let mut at = start + 1;
667    while let Some(byte) = bytes.remove(&at) {
668        run.push(byte);
669        at += 1;
670    }
671    Some(run)
672}