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};
30use std::fmt;
31
32use rucc_base::{Interner, Symbol};
33use rucc_diag::{Diagnostic, Span};
34use rucc_ir::{
35    Alias, AttrSet, DataList, Datum, FpContract, Func, Global, Imm, Linkage as IrLinkage, Meta,
36    Module, Reloc, SymbolRef, TlsModel, Type, Visibility as IrVisibility,
37};
38use rucc_sema::{
39    Base, Const, Conversion, DeclId, DeclKind, Definition, Eval, ExprId, ExprKind, InitEntry,
40    InitList, Linkage, StorageDuration, StrId, Tast, Visibility,
41};
42use rucc_target::TargetInfo;
43use rucc_types::{TypeId, TypeKind, Types, compatible};
44
45use crate::abi::{self, Plan};
46use crate::aliasing;
47use crate::body;
48use crate::directives;
49use crate::reach;
50use crate::repr;
51
52/// Which functions get a stack protector, which is what the `-fstack-protector` family decides.
53///
54/// The question is about the locals a function has, so it is answered here and not in the back
55/// end: by the time a frame is laid out the types are gone and every local is a size and an
56/// alignment. What the back end then does about the answer is its own business, and it is carried
57/// to it as [`rucc_ir::AttrSet::STACK_PROTECT`] on the function.
58///
59/// The names are gcc's, and so are the rules. A build that has been compiled with one of these for
60/// twenty years is entitled to the same set of protected functions from a compiler claiming to be
61/// compatible, because the ones left out are the ones an exploit goes looking for.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
63pub enum Protector {
64    /// None of them, which is `-fno-stack-protector` and what a command line that says nothing
65    /// gets.
66    #[default]
67    None,
68    /// A function with a local array of at least eight bytes, or one whose stack grows while it
69    /// runs. `-fstack-protector`, which is the original and the narrowest.
70    Buffers,
71    /// Any of those, and any function with a local array at all, a local holding one, or a local
72    /// whose address is taken. `-fstack-protector-strong`, which is what every distribution builds
73    /// its packages with and therefore the one a real build line carries.
74    Strong,
75    /// Every function that has a frame at all. `-fstack-protector-all`.
76    All,
77}
78
79/// What overflows rather than being undefined, which is `-fwrapv` and its relatives.
80///
81/// Every licence the walk grants the optimizer about overflow is one flag on one instruction, and
82/// withdrawing a licence is not setting it. So this is read where the flags are chosen and nowhere
83/// else, and a unit built with either of these is a unit whose IR carries less rather than a unit
84/// the passes are told something extra about. That is also what makes it correct across link time
85/// optimization: a body from a unit that wraps and a body from one that does not keep their own
86/// answers when they end up in the same module.
87///
88/// `-ftrapv` is the exception and is the reason this is not simply two flags. It is the other
89/// answer to the question `-fwrapv` answers, and it is the only one of the three that asks for
90/// something to be generated rather than for something to be left out.
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
92pub struct Wrapping {
93    /// Whether signed arithmetic wraps, from `-fwrapv`. Set, and an add, a subtract, a multiply, a
94    /// shift and a negation in a signed type stop saying they do not wrap.
95    pub signed: bool,
96    /// Whether pointer arithmetic wraps, from `-fwrapv-pointer`. Set, and the multiply that turns
97    /// an index into a number of bytes stops saying so.
98    ///
99    /// That multiply is the whole of it here, because the addition itself never claimed anything: a
100    /// `ptradd` carries no flags in this IR and no pass reads one off it.
101    pub pointer: bool,
102    /// Whether a signed overflow stops the program, from `-ftrapv`. Set, and an add, a subtract, a
103    /// multiply and a negation in a signed type become calls to the routine in the runtime that
104    /// does the arithmetic and checks it.
105    ///
106    /// Never set at the same time as [`Wrapping::signed`], because a program cannot both wrap and
107    /// stop. The driver is what keeps that true.
108    pub trap: bool,
109}
110
111/// Everything the walk reads, which is a checked translation unit and the target it is for.
112///
113/// The interner is mutable because the walk invents names the program never wrote: the label a
114/// string literal is emitted under, and the mangled name of a function-scope `static`.
115pub struct Context<'a> {
116    /// The typed tree.
117    pub tast: &'a Tast,
118    /// The types it points into.
119    pub types: &'a Types,
120    /// What is being compiled for, which is where every width and every alignment comes from.
121    pub target: &'a TargetInfo,
122    /// The name table.
123    pub names: &'a mut Interner,
124    /// What a name that no declaration of it said anything about gets, which is `-fvisibility=`.
125    ///
126    /// A fact about the compilation rather than about any declaration, which is why it arrives
127    /// here rather than on the tree: the checker knows what was written and this knows what the
128    /// command line asked for, and the answer is the first of those where there is one.
129    pub visibility: IrVisibility,
130    /// Which functions get a stack protector, which is `-fstack-protector` and its relatives.
131    pub protector: Protector,
132    /// What overflows rather than being undefined, which is `-fwrapv` and its relatives.
133    ///
134    /// A fact about the compilation for the same reason the two above it are: what was written is
135    /// on the tree and what was asked for is on the command line.
136    pub wrapping: Wrapping,
137    /// Whether an access carries the node for the type it goes through, which is
138    /// `-fstrict-aliasing` and is on unless `-fno-strict-aliasing` cleared it.
139    ///
140    /// Clearing it here rather than in the optimizer is what makes the flag one condition in one
141    /// place: an access with no node conflicts with every other access, so a unit built with the
142    /// flag off is a unit whose IR says less rather than a unit the passes are told something
143    /// extra about. That is also what keeps it right across link time optimization, the way
144    /// [`Context::wrapping`] is: a body from a unit that named its types and a body from one that
145    /// did not keep their own answers when they end up in the same module.
146    pub aliasing: bool,
147    /// Whether an access says how far the padding after it reaches, which is
148    /// `-fsafety-init=nopadding` and is what a build with no safety tier gets too, since nothing
149    /// reads the number then.
150    ///
151    /// Here rather than in the safety pass for the reason [`Context::aliasing`] is here: what the
152    /// number is takes a record's layout, and the layout is a thing the walk has in hand and the
153    /// pass over the IR does not. The pass reads it and does not decide anything, which keeps the
154    /// flag one condition in one place and keeps it right across link time optimization.
155    pub padding: bool,
156    /// How far a multiply and an addition may be fused into one rounding, which is
157    /// `-ffp-contract=`.
158    ///
159    /// A fact about the compilation like the ones above it, and the one of them that is written
160    /// down rather than acted on: it goes onto every function with a body as
161    /// [`rucc_ir::Attrs::fp_contract`], because the place that would fuse anything is the code
162    /// generator and by the time it runs the command line is gone and the two operations it might
163    /// fuse may have come from different statements.
164    pub contract: FpContract,
165    /// How a file named by a `.incbin` in an `asm` at file scope is read, given the name as the
166    /// template wrote it and handing back either the bytes or what went wrong.
167    ///
168    /// Passed in rather than reached for, because the walk has no business opening files and
169    /// because a caller that put its sources somewhere other than a disk has put this file there
170    /// too. The name is resolved the way an assembler resolves it, which is against the directory
171    /// the compiler was run in and not against the directory the source was found in.
172    pub read: &'a mut dyn FnMut(&str) -> Result<Vec<u8>, String>,
173}
174
175// Written out rather than derived because a closure has no `Debug`, and printing one would say
176// nothing anyway. What is worth reading here is the settings, so those are what this prints.
177impl fmt::Debug for Context<'_> {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        f.debug_struct("Context")
180            .field("visibility", &self.visibility)
181            .field("protector", &self.protector)
182            .field("wrapping", &self.wrapping)
183            .field("aliasing", &self.aliasing)
184            .field("padding", &self.padding)
185            .field("contract", &self.contract)
186            .finish_non_exhaustive()
187    }
188}
189
190/// What the walk produced.
191#[derive(Debug)]
192pub struct Lowered {
193    /// The module, which is complete even when something was reported: a construct that is not
194    /// supported yet leaves the rest of the function around it intact.
195    pub module: Module,
196    /// What was reported, in the order it was found.
197    pub diagnostics: Vec<Diagnostic>,
198}
199
200/// Walks a checked translation unit and builds the IR for it.
201///
202/// `name` is the module's name, which is the file the tree came from.
203#[must_use]
204pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
205    let Context {
206        tast,
207        types,
208        target,
209        names,
210        visibility,
211        protector,
212        wrapping,
213        aliasing,
214        padding,
215        contract,
216        read,
217    } = cx;
218    let module = Module::new(names.intern(name), target);
219    let mut unit = Unit {
220        tast,
221        types,
222        target,
223        names,
224        visibility,
225        protector,
226        wrapping,
227        aliasing,
228        padding,
229        cliques: 0,
230        tree: aliasing::Tree::default(),
231        contract,
232        read,
233        module,
234        diagnostics: Vec::new(),
235        strings: HashMap::new(),
236        statics: HashMap::new(),
237        done: HashSet::new(),
238        aliases: Vec::new(),
239        aliased: HashSet::new(),
240        reachable: reach::reachable(tast),
241    };
242    unit.run();
243    Lowered { module: unit.module, diagnostics: unit.diagnostics }
244}
245
246/// The walk over one translation unit, and everything it has built so far.
247pub(crate) struct Unit<'a> {
248    pub(crate) tast: &'a Tast,
249    pub(crate) types: &'a Types,
250    pub(crate) target: &'a TargetInfo,
251    pub(crate) names: &'a mut Interner,
252    /// What a name no declaration said anything about gets. See [`Context::visibility`].
253    visibility: IrVisibility,
254    /// Which functions get a stack protector. See [`Context::protector`].
255    pub(crate) protector: Protector,
256    /// What wraps rather than being undefined. See [`Context::wrapping`].
257    pub(crate) wrapping: Wrapping,
258    /// Whether an access names the type it goes through. See [`Context::aliasing`].
259    aliasing: bool,
260    /// Whether an access says how far the padding after it reaches. See [`Context::padding`].
261    pub(crate) padding: bool,
262    /// How many `restrict` scopes have been handed out, which is a number the whole module shares
263    /// so that no two functions promise different things with the same one. See
264    /// [`restrict`](mod@crate::restrict) for why that matters before there is an inliner.
265    pub(crate) cliques: u16,
266    /// The type based aliasing tree built so far, which is one per module.
267    tree: aliasing::Tree,
268    /// How far a multiply and an addition may be fused. See [`Context::contract`].
269    pub(crate) contract: FpContract,
270    /// How a file a `.incbin` names is read. See [`Context::read`].
271    read: &'a mut dyn FnMut(&str) -> Result<Vec<u8>, String>,
272    pub(crate) module: Module,
273    pub(crate) diagnostics: Vec<Diagnostic>,
274    /// The global each string literal was emitted as, so that two mentions of one literal are
275    /// one object.
276    strings: HashMap<StrId, Symbol>,
277    /// The name each object with no linkage was given.
278    statics: HashMap<DeclId, Symbol>,
279    /// What has been emitted, because a redeclaration is the same declaration seen twice.
280    done: HashSet<DeclId>,
281    /// The declarations that are a second name for something rather than a thing of their own,
282    /// in the order the file made them.
283    ///
284    /// Held back rather than emitted where they are met, because what an alias points at may be
285    /// written below it and whether anything defines it is a question only the whole file
286    /// answers.
287    aliases: Vec<DeclId>,
288    /// The symbols something in the file is a second name for.
289    ///
290    /// A `static` function nothing calls is not emitted, and being what an alias points at is a
291    /// reason to emit one that no reference in the file says: the string an alias names is not a
292    /// use of anything as far as the walk over the tree is concerned.
293    aliased: HashSet<Symbol>,
294    /// What something in the file reaches, which is what decides whether a function with
295    /// internal linkage is emitted at all.
296    reachable: HashSet<DeclId>,
297}
298
299// The debug is by hand and short: a translation unit is not something anybody wants printed as
300// a `{:?}`, and the module has a printer of its own for when they do.
301impl fmt::Debug for Unit<'_> {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        f.debug_struct("Unit")
304            .field("module", &self.module.counts())
305            .field("diagnostics", &self.diagnostics.len())
306            .finish()
307    }
308}
309
310impl Unit<'_> {
311    /// The aliasing node an access through `ty` carries, and [`None`] when it carries none.
312    ///
313    /// [`None`] is also every answer under `-fno-strict-aliasing`, which is the whole of what that
314    /// flag does here. See [`aliasing`](mod@crate::aliasing) for which types have a node.
315    pub(crate) fn alias_node(&mut self, ty: TypeId) -> Option<Meta> {
316        if !self.aliasing {
317            return None;
318        }
319        self.tree.node(&mut self.module, self.names, self.types, ty)
320    }
321
322    /// The root of the aliasing tree, which is the node an access that may be punned carries.
323    ///
324    /// The root is `char` and it conflicts with everything, so an access carrying it is an access
325    /// nothing may be reordered across and, in the type plane, a byte nothing has settled the type
326    /// of. `crate::body` says which accesses those are.
327    pub(crate) fn alias_root(&mut self) -> Option<Meta> {
328        if !self.aliasing {
329            return None;
330        }
331        Some(self.tree.root(&mut self.module, self.names))
332    }
333
334    /// Every declaration the file made, in the order it made them.
335    fn run(&mut self) {
336        self.file_asms();
337        self.find_aliased();
338        for index in 0..self.tast.top_level().len() {
339            let decl = self.tast.top_level()[index];
340            if !self.done.insert(decl) {
341                continue;
342            }
343            match self.tast[decl].kind {
344                DeclKind::Function => self.function(decl),
345                DeclKind::Object => self.object(decl),
346            }
347        }
348        for index in 0..self.aliases.len() {
349            self.alias(self.aliases[index]);
350        }
351    }
352
353    /// The `asm` written at file scope, read into the globals they define.
354    ///
355    /// Ahead of the declarations rather than among them. A block usually names more than one
356    /// thing and means them to be next to each other, the object writer lays globals out in the
357    /// order the module holds them, and adding a block's globals together is what makes them a
358    /// run. A declaration of one of those names below the block then finds a definition already
359    /// there and leaves it alone, which is the division the program wrote: the template says what
360    /// the bytes are and the C declaration says what they are to be read as.
361    fn file_asms(&mut self) {
362        for index in 0..self.tast.file_asms().len() {
363            let asm = self.tast.file_asms()[index];
364            let template = self.spelled(asm.template);
365            let pieces = match directives::assemble(&template, &mut *self.read) {
366                Ok(pieces) => pieces,
367                Err(directives::Failed::Unsupported(what)) => {
368                    self.unsupported(&format!("{what} in an `asm` at file scope"), asm.span);
369                    continue;
370                }
371                Err(directives::Failed::Missing(name, why)) => {
372                    let message = format!("cannot open '{name}' for reading: {why}");
373                    self.diagnostics.push(Diagnostic::error(message, asm.span).with_code("E0702"));
374                    continue;
375                }
376            };
377            for piece in pieces {
378                self.piece(piece);
379            }
380        }
381    }
382
383    /// One global an `asm` at file scope defined.
384    fn piece(&mut self, piece: directives::Piece) {
385        let symbol = self.names.intern(&piece.name);
386        let mut global = Global::new(symbol, piece.size, piece.align.max(1));
387        global.linkage = piece.linkage;
388        global.visibility = piece.visibility;
389        let bss = matches!(piece.section, directives::Section::Bss);
390        match piece.section {
391            // Which of the sections the object writer has an answer of its own for. Asking for
392            // `.rodata` by name would produce a second section with that spelling and with the
393            // flags of a writable one, so what is said here is what the global is instead.
394            directives::Section::ReadOnly => global.constant = true,
395            directives::Section::Data | directives::Section::Bss => {}
396            directives::Section::Named(name) => global.section = Some(self.names.intern(&name)),
397            // Refused where the template was read, since what goes in that section is
398            // instructions and there is nothing here that makes one.
399            directives::Section::Text => return,
400        }
401        let mut data = Vec::with_capacity(piece.items.len());
402        if piece.items.is_empty() && bss {
403            // A label at the end of the zero filled section, which has nothing under it and
404            // still has to land there rather than in the section of written bytes. An image of
405            // no zeros is what says so, since being all zeros is how a global asks for that
406            // section and an empty image asks for nothing.
407            data.push(Datum::Zero(0));
408        }
409        for item in piece.items {
410            data.push(match item {
411                directives::Item::Bytes(bytes) => Datum::Bytes(self.module.push_bytes(&bytes)),
412                directives::Item::Int { width, value } => {
413                    let ty = Type::int(u32::from(width) * 8);
414                    Datum::Scalar {
415                        ty,
416                        value: self.module.add_imm(Imm::int(i128::from(value), ty)),
417                    }
418                }
419                directives::Item::Zero(bytes) => Datum::Zero(bytes),
420            });
421        }
422        global.init = Some(self.module.push_data(&data));
423        self.place_global(global);
424    }
425
426    /// Which symbols the file gives a second name to, before anything is emitted.
427    ///
428    /// Ahead of the walk rather than during it, because a `static` function is emitted or not on
429    /// the strength of what reaches it and the alias that reaches one may be written below it.
430    fn find_aliased(&mut self) {
431        for index in 0..self.tast.top_level().len() {
432            let decl = self.tast.top_level()[index];
433            let Some(target) = self.tast[decl].alias else { continue };
434            let spelling = self.spelled(target);
435            let symbol = self.names.intern(&spelling);
436            self.aliased.insert(symbol);
437        }
438    }
439
440    /// The bytes of a string literal as a name, which is what a symbol in an attribute is.
441    fn spelled(&self, id: StrId) -> String {
442        self.tast[id].elements.iter().filter_map(|&unit| char::from_u32(unit)).collect()
443    }
444
445    /// One object with static storage duration.
446    fn object(&mut self, decl: DeclId) {
447        let tast = self.tast;
448        let node = &tast[decl];
449        let (ty, state, init) = (node.ty, node.state, node.init);
450        let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
451        let span = tast.decl_span(decl);
452        if duration == StorageDuration::Automatic {
453            // A block-scope object with automatic storage is a slot or a value in the function
454            // that declares it, and the body is what makes it. Nothing is emitted here.
455            return;
456        }
457        // A second name for something else is not an object of its own, so nothing is laid out
458        // and no image is built. It is held back until the rest of the file has been walked,
459        // because what it points at may be below it.
460        if node.alias.is_some() {
461            self.aliases.push(decl);
462            return;
463        }
464
465        let symbol = self.symbol_of(decl);
466        let size = repr::size_of(self.types, self.target, ty);
467        let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
468        let mut global = Global::new(symbol, size, align);
469        global.linkage = match linkage {
470            Linkage::External => IrLinkage::External,
471            Linkage::Internal | Linkage::None => IrLinkage::Internal,
472        };
473        global.visibility = self.seen(decl);
474        global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
475        global.constant = repr::is_read_only(self.types, ty);
476        global.init = match state {
477            // `extern int x;` and nothing else names an object another translation unit
478            // defines. The global is here so that a reference to it has something to resolve
479            // against, and it has no image, which is what makes it a declaration.
480            Definition::Declared => None,
481            Definition::Tentative => Some(self.zeros(size)),
482            Definition::Defined => {
483                let (data, covered) = self.image(init, size, span);
484                // The object is as large as its image when the image is the larger of the two.
485                // A structure whose last member is a flexible array is the only way that
486                // happens: `sizeof` answers without the array and an initializer that fills it
487                // makes an object big enough to hold what was written. C 6.7.2.1p18 leaves the
488                // size to the implementation, gcc grows the object, and this does the same
489                // rather than hand the linker a size the image does not fit in.
490                global.size = size.max(covered);
491                Some(data)
492            }
493        };
494        self.place_global(global);
495    }
496
497    /// One function, with its body when it has one.
498    fn function(&mut self, decl: DeclId) {
499        let tast = self.tast;
500        let node = &tast[decl];
501        let (ty, linkage, body, align) = (node.ty, node.linkage, node.body, node.alignment);
502        let noreturn = node.noreturn;
503        let span = tast.decl_span(decl);
504        if node.name.is_none() {
505            return;
506        }
507        // The same as for an object: a second name is not a function of its own, and it is held
508        // back until what it points at has been emitted.
509        if node.alias.is_some() {
510            self.aliases.push(decl);
511            return;
512        }
513        // Which asks the one question the reference to it asks, so that a declaration that
514        // renamed the symbol renames the definition as well and the two still meet.
515        let name = self.symbol_of(decl);
516        if self.is_dropped(decl, name) {
517            return;
518        }
519        let Some(plan) = self.plan(ty, &[], span) else { return };
520
521        let mut func = Func::new(name, plan.signature.clone());
522        func.align = align;
523        // The one thing a declaration says that nobody downstream can work out for themselves.
524        // What `abort` does belongs to `abort`, and a translation unit that only declares it has
525        // nothing to look at, so the claim has to travel on the declaration or not at all.
526        if noreturn {
527            func.attrs.set |= AttrSet::NORETURN;
528        }
529        func.linkage = match linkage {
530            Linkage::Internal | Linkage::None => IrLinkage::Internal,
531            Linkage::External => IrLinkage::External,
532        };
533        func.visibility = self.seen(decl);
534        // An inline definition is not an external definition, so what goes in the module is the
535        // declaration and not the body. C 6.7.4p7 says the calls in this unit go to the definition
536        // some other unit holds, which is what the declaration gives them, and glibc's headers
537        // rely on it: every one of their inline definitions would otherwise be a second definition
538        // of a name the library already defines.
539        if body.is_some() && node.inline.emits() {
540            body::lower(self, decl, &mut func, &plan);
541        }
542        self.place_func(func);
543    }
544
545    /// Puts a function in the module under a name something may already be under.
546    ///
547    /// Two declarations of one identifier were merged before this, so the only way one name
548    /// arrives twice is an assembler name that renames one identifier onto another: a
549    /// declaration of `f` renamed to `g` beside a definition of `g` is one symbol written two
550    /// ways, which is what the program asked for and what the linker is going to see. The
551    /// definition wins wherever there is one, since what the declaration is here for is to give
552    /// the calls something to resolve against and the definition does that as well.
553    ///
554    /// A name already carrying a definition keeps it. That is the program defining one symbol
555    /// twice, and the assembler says so with the name in front of it, which is a better message
556    /// than anything available here.
557    fn place_func(&mut self, func: Func) {
558        match self.module.lookup(func.name) {
559            None => {
560                self.module.add_func(func);
561            }
562            Some(SymbolRef::Func(id))
563                if self.module[id].is_declaration() && !func.is_declaration() =>
564            {
565                self.module[id] = func;
566            }
567            Some(_) => {}
568        }
569    }
570
571    /// One declaration that is a second name for something the same file defines.
572    ///
573    /// Emitted after everything else, so the target is looked up in a module that already holds
574    /// whatever the file defines whether it was written above the alias or below it.
575    ///
576    /// The target has to be defined here and not merely declared, which is gcc's rule and is
577    /// what the object format can express: an alias is a symbol at another symbol's address, and
578    /// a name this file does not define has no address for one to be at. A program that writes
579    /// an alias of something in another object wants a reference rather than a definition, and
580    /// what it gets from gcc is this same error rather than a name the linker cannot resolve.
581    fn alias(&mut self, decl: DeclId) {
582        let Some(written) = self.tast[decl].alias else { return };
583        let span = self.tast.decl_span(decl);
584        let name = self.symbol_of(decl);
585        let spelling = self.spelled(written);
586        let target = self.names.intern(&spelling);
587        let spelled = self.names.resolve(name).to_owned();
588        if name == target {
589            let what = format!("'{spelled}' is aliased to itself");
590            self.diagnostics.push(Diagnostic::error(what, span).with_code("E0697"));
591            return;
592        }
593        let defined = match self.module.lookup(target) {
594            Some(SymbolRef::Func(id)) => !self.module[id].is_declaration(),
595            Some(SymbolRef::Global(id)) => self.module[id].init.is_some(),
596            // A chain of them is a thing gcc takes and this does not yet, because resolving one
597            // wants the aliases put in an order that the file they were written in need not be
598            // in. It is reported rather than written out as a name pointing at a name.
599            Some(SymbolRef::Alias(_)) | None => false,
600        };
601        if !defined {
602            let what = format!("'{spelled}' is aliased to undefined symbol '{spelling}'");
603            let note = "the target of an alias has to be defined in this same file, since an \
604                        alias is a second name for an address and not a reference to one";
605            let refused = Diagnostic::error(what, span).with_code("E0697");
606            self.diagnostics.push(refused.note(note, span));
607            return;
608        }
609        // Something already under this name, which is the program defining one symbol twice. The
610        // definition that is there stands, the way it does for a function and for an object.
611        if self.module.lookup(name).is_some() {
612            return;
613        }
614        let mut alias = Alias::new(name, target);
615        alias.linkage = match self.tast[decl].linkage {
616            Linkage::Internal | Linkage::None => IrLinkage::Internal,
617            Linkage::External => IrLinkage::External,
618        };
619        // Its own answer, because the attribute is written on the alias and an alias is a symbol
620        // of its own. `weak, alias, visibility("hidden")` is a name a library keeps to itself
621        // while the thing it points at stays exported, which is how glibc writes half of them.
622        alias.visibility = self.seen(decl);
623        self.module.add_alias(alias);
624    }
625
626    /// How far a name reaches outside a shared library, which is what a declaration of it said
627    /// where one said anything and what the command line asked for where none did.
628    ///
629    /// gcc's `-fvisibility=` is written as the default rather than as an override, so the
630    /// attribute wins wherever it was written, and that is the whole reason a library compiled
631    /// with `-fvisibility=hidden` can still export the dozen names it means to export.
632    ///
633    /// Every symbol gets an answer, including a declaration of something defined elsewhere. That
634    /// is what gcc does too and it is not a technicality: a hidden reference is one the link has
635    /// to satisfy inside the library, which is the half of the flag that makes the calls cheaper
636    /// rather than the half that shortens the table.
637    fn seen(&self, decl: DeclId) -> IrVisibility {
638        match self.tast[decl].visibility {
639            Some(Visibility::Default) => IrVisibility::Default,
640            Some(Visibility::Hidden) => IrVisibility::Hidden,
641            Some(Visibility::Protected) => IrVisibility::Protected,
642            None => self.visibility,
643        }
644    }
645
646    /// The same for an object, where a global with no image is the declaration.
647    fn place_global(&mut self, global: Global) {
648        match self.module.lookup(global.name) {
649            None => {
650                self.module.add_global(global);
651            }
652            Some(SymbolRef::Global(id))
653                if self.module[id].init.is_none() && global.init.is_some() =>
654            {
655                self.module[id] = global;
656            }
657            Some(_) => {}
658        }
659    }
660
661    /// Whether this function is one nothing can call, which is the set that is not emitted.
662    ///
663    /// A name with internal linkage is not visible to another translation unit, so a definition
664    /// of one that nothing here refers to is a definition of something that can never run.
665    /// [`reach`](mod@crate::reach) is what worked out which those are, and an attribute that asks
666    /// for the definition to be kept has already been read into the answer.
667    ///
668    /// A second name for it is the one reason to keep it that the walk over the tree cannot see,
669    /// since what an alias points at is a string and not a reference to anything. So the symbol
670    /// is what is asked about here rather than the declaration: an alias names what the linker
671    /// will look for, which is what a declaration that renamed itself with `__asm__` is under.
672    ///
673    /// Nothing is said about it. gcc has `-Wunused-function` for a `static` function nobody
674    /// wrote a call to, which is a warning about the program, and this is not that: the header
675    /// that defines six of them is not the file being compiled and its author is not the person
676    /// reading the output.
677    fn is_dropped(&self, decl: DeclId, symbol: Symbol) -> bool {
678        self.tast[decl].linkage != Linkage::External
679            && !self.reachable.contains(&decl)
680            && !self.aliased.contains(&symbol)
681    }
682
683    /// How everything a call to this function type hands over travels, and [`None`] for one the
684    /// walk cannot make.
685    ///
686    /// `actual` is the types of the arguments at a call site, which matter only past the end of
687    /// the prototype: what a variadic argument does is decided from what was written there, and
688    /// there is no parameter to decide it from. A definition passes nothing for it.
689    pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
690        self.plan_with(ty, actual, false, span)
691    }
692
693    /// The same, as the call site sees it rather than as the function does.
694    ///
695    /// The two differ for a type that is not a prototype. An old style definition is the one of
696    /// those that knows what its parameters are, and 6.5.2.2p6 checks a call against a prototype
697    /// and against nothing at all otherwise, so a parameter it disagrees with does not make the
698    /// call wrong and cannot be what the argument travels as either: the value at the call is
699    /// the argument's own type and nothing converted it. So a parameter the argument facing it
700    /// is compatible with is used, which is the usual case and is what makes the call go to the
701    /// name, and one it is not compatible with gives way to what was actually written. A call
702    /// like that is undefined behaviour if control reaches it and the file still has to
703    /// translate, which is the same position [`Body::direct`](crate::body) already takes.
704    pub(crate) fn call_plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
705        self.plan_with(ty, actual, true, span)
706    }
707
708    fn plan_with(
709        &mut self,
710        ty: TypeId,
711        actual: &[TypeId],
712        at_call: bool,
713        span: Span,
714    ) -> Option<Plan> {
715        let canonical = self.types.canonical(ty);
716        let canonical = match self.types.kind(canonical) {
717            // A call goes through a pointer to a function, and the type in hand may be either.
718            TypeKind::Pointer(pointee) => self.types.canonical(pointee),
719            _ => canonical,
720        };
721        let TypeKind::Function(id) = self.types.kind(canonical) else {
722            self.unsupported("a call through something that is not a function", span);
723            return None;
724        };
725        let signature = self.types.signature(id);
726        let ret = signature.ret;
727        // A function declared without a prototype takes what it is given, which is what a
728        // signature with no parameters and no end to them says. C23 removed these and this is
729        // what `int f();` means in every dialect before it.
730        let variadic = signature.variadic || !signature.prototyped;
731        let params = if at_call && !signature.prototyped {
732            // An argument past the end of the list has no parameter to travel as, which is what
733            // a call to an unprototyped function with more arguments than the definition takes
734            // is, so the list ends where the arguments do.
735            signature
736                .params
737                .iter()
738                .zip(actual)
739                .map(|(&param, &arg)| if compatible(self.types, param, arg) { param } else { arg })
740                .collect()
741        } else {
742            signature.params.clone()
743        };
744
745        match abi::plan(self.types, self.target, ret, &params, actual, variadic) {
746            Ok(plan) => Some(plan),
747            Err(what) => {
748                self.unsupported(what, span);
749                None
750            }
751        }
752    }
753
754    /// The image of an initializer: the entries in ascending order, with the gaps zeroed, and
755    /// how many bytes it covers.
756    ///
757    /// The count is the size that was asked for except when a flexible array member was given
758    /// something to hold, which is the one case where an image is larger than the type it is an
759    /// image of.
760    pub(crate) fn image(
761        &mut self,
762        init: Option<InitList>,
763        size: u64,
764        span: Span,
765    ) -> (DataList, u64) {
766        let Some(init) = init else { return (self.zeros(size), size) };
767        let (data, at) = self.pieces(init, size, span);
768        (self.module.push_data(&data), at)
769    }
770
771    /// The data an image is made of, before it becomes a [`DataList`].
772    ///
773    /// This is apart from [`Self::image`] so that an image can be built inside another one,
774    /// which is what a compound literal used as a value in an initializer needs.
775    fn pieces(&mut self, init: InitList, size: u64, span: Span) -> (Vec<Datum>, u64) {
776        let entries = self.in_image_order(&self.tast[init]);
777        let mut packed = self.packed(&entries, size);
778        let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
779        let mut at = 0;
780        for entry in entries {
781            let piece = self.entry(entry, &mut packed, size);
782            if piece.is_empty() {
783                continue;
784            }
785            let covered: u64 = piece.iter().map(|datum| datum.size(&self.module)).sum();
786            match entry.offset.cmp(&at) {
787                Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
788                // An entry that begins inside the one before it, which is neither the same
789                // place nor a later one. A union whose members are initialized through two
790                // designators is the way to write it. The earlier bytes are already in the
791                // list and the image cannot take them out again, so this is refused, and
792                // nothing here is wrong enough to drop the rest of the image.
793                Ordering::Less => {
794                    self.unsupported("an initializer that writes over an earlier one", span);
795                    continue;
796                }
797                Ordering::Equal => {}
798            }
799            at = entry.offset + covered;
800            data.extend(piece);
801        }
802        if at < size {
803            // The tail of a partly initialized object, which C says is zero. So is the tail of
804            // an array the initializer did not fill, and so is every byte of padding.
805            data.push(Datum::Zero(size - at));
806            at = size;
807        }
808        (data, at)
809    }
810
811    /// The entries an image is written from, which is not the order they were written in.
812    ///
813    /// A designator names a place, and the places may be named in any order at all:
814    /// `{ .b = 2, .a = 1 }` is the same object as `{ .a = 1, .b = 2 }` and C says so in as many
815    /// words. An image is bytes in ascending order, so the entries are put in that order here.
816    /// The sort is stable, which is what makes the rest of the rule work: naming one place
817    /// twice is legal and the last of them is the one that stands, so among the entries at one
818    /// offset the written order is kept and all but the last are dropped.
819    ///
820    /// A bit-field is never dropped, because several of them share one offset without writing
821    /// over anything. Which bytes they came to is settled by [`Self::packed`] before this runs
822    /// and the whole run goes in under the first entry that has a bit in it.
823    fn in_image_order(&self, entries: &[InitEntry]) -> Vec<InitEntry> {
824        let mut sorted = entries.to_vec();
825        sorted.sort_by_key(|entry| entry.offset);
826        let mut kept: Vec<InitEntry> = Vec::with_capacity(sorted.len());
827        for entry in sorted {
828            if !entry.is_bit_field() {
829                let over = |last: &InitEntry| last.offset == entry.offset && !last.is_bit_field();
830                while kept.last().is_some_and(over) {
831                    kept.pop();
832                }
833            }
834            kept.push(entry);
835        }
836        kept
837    }
838
839    /// What one entry of an initializer puts in the image.
840    ///
841    /// A bit-field is not a datum of its own, because two of them can live in one byte and an
842    /// image is written in bytes. They were put together into their bytes by [`Self::packed`]
843    /// before this ran, and the whole run of bytes goes in under the first entry that lies in
844    /// it, which is why a later one in the same run answers with nothing.
845    ///
846    /// The zeroes at the end of a run are left off it, and a run that is nothing but zeroes
847    /// answers with nothing at all. Either way the gap before the next entry covers them, which
848    /// is the same image and is a smaller one to carry, and it is what keeps an object whose
849    /// bit-fields are all zero in `.bss`. A zero at the front of a run or inside one stays, since
850    /// that is where the run starts and what makes it one run. The run comes out of the map
851    /// whatever is in it, so a later entry lying in it answers with nothing for the usual reason
852    /// rather than writing the run a second time.
853    ///
854    /// An entry is usually one datum and a compound literal read is the reason the answer is a
855    /// list: that entry is a whole object and puts as many data in as the object it is.
856    fn entry(&mut self, entry: InitEntry, packed: &mut BTreeMap<u64, u8>, size: u64) -> Vec<Datum> {
857        if entry.is_bit_field() {
858            let Some(bytes) = take_run(packed, entry.offset) else { return Vec::new() };
859            let Some(last) = bytes.iter().rposition(|&byte| byte != 0) else { return Vec::new() };
860            return vec![Datum::Bytes(self.module.push_bytes(&bytes[..=last]))];
861        }
862        if let Some(literal) = self.literal_read(entry.value) {
863            return self.literal_image(literal, self.tast.expr_span(entry.value));
864        }
865        // How much room is left in the object, which is what a string literal longer than the
866        // array it initializes is cut down to. An entry that begins where the object ends is the
867        // initializer of a flexible array member, and there the object grows to hold what was
868        // written rather than the value being cut to fit, so nothing is taken off it.
869        let room = if entry.offset < size { size - entry.offset } else { u64::MAX };
870        self.datum(entry.value, room).into_iter().collect()
871    }
872
873    /// The compound literal an entry reads, if that is what the entry is.
874    ///
875    /// Reading an object is a node of its own, so a literal used as a value comes through as a
876    /// read of a literal. A literal whose address is taken is not a read and is not this: that
877    /// one folds to an address and goes in as a relocation, with the object it points at emitted
878    /// on its own.
879    fn literal_read(&self, value: ExprId) -> Option<DeclId> {
880        let ExprKind::Convert { kind: Conversion::Lvalue, operand } = self.tast[value].kind else {
881            return None;
882        };
883        match self.tast[operand].kind {
884            ExprKind::CompoundLiteral(decl) => Some(decl),
885            _ => None,
886        }
887    }
888
889    /// The bytes a compound literal contributes where it is read, which are its own image.
890    ///
891    /// The literal has static storage duration here, since a file-scope initializer is the only
892    /// place this is reached from, and C 6.7.11p4 is what lets it stand as a constant element.
893    /// Its own initializer is built at the offset the entry is at, so the parent image ends up
894    /// with the literal's bytes laid into it rather than a name pointing at a second object.
895    fn literal_image(&mut self, literal: DeclId, span: Span) -> Vec<Datum> {
896        let size = repr::size_of(self.types, self.target, self.tast[literal].ty);
897        let Some(init) = self.tast[literal].init else {
898            return if size == 0 { Vec::new() } else { vec![Datum::Zero(size)] };
899        };
900        self.pieces(init, size, span).0
901    }
902
903    /// The bit-fields of an initializer, put together into the bytes they lie in.
904    ///
905    /// Every byte a field lies in is in the map, whatever the bits it put there are. It is
906    /// tempting to leave a zero byte out, on the grounds that what an image does not say is zero
907    /// anyway, and it is wrong: the run a field's bytes make is taken out of the map from the
908    /// byte the field starts at, so a field whose first byte happens to be zero would have its
909    /// whole run left behind and `struct { unsigned f : 20; } x = { 0x12300 };` would read as
910    /// zero. A run that is all zeroes is written as zeroes by [`Self::entry`], so an object that
911    /// really is zero still costs nothing in the image.
912    ///
913    /// A field named twice takes only the bits of the field, so the last of them stands and does
914    /// not read as the two values together.
915    fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
916        let mut bytes = BTreeMap::new();
917        for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
918            let Some(folded) = self.fold(entry.value) else { continue };
919            let Const::Int(number) = folded else {
920                let span = self.tast.expr_span(entry.value);
921                let what = "a bit-field initialized by something that is not an integer";
922                self.unsupported(what, span);
923                continue;
924            };
925            let width = entry.bit_width;
926            let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
927            let mut mask = ones << entry.bit_offset;
928            let mut placed = ((number as u128) & ones) << entry.bit_offset;
929            let mut at = entry.offset;
930            while mask != 0 && at < size {
931                let (bits, keep) = ((placed & 0xff) as u8, !((mask & 0xff) as u8));
932                let byte = bytes.entry(at).or_insert(0);
933                *byte = (*byte & keep) | bits;
934                mask >>= 8;
935                placed >>= 8;
936                at += 1;
937            }
938        }
939        bytes
940    }
941
942    /// One entry of an image, given how many bytes are left in the object it goes in.
943    fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
944        let tast = self.tast;
945        let ty = tast[value].ty;
946        let span = tast.expr_span(value);
947        if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
948            // An array in an initializer is a string literal initializing it, because that is
949            // the only way an array is ever a value. `char s[2] = "hi";` drops the terminator,
950            // which is the one case where the literal is longer than what it initializes, and
951            // the front end has already given the value the type of the array it is filling, so
952            // the type is what says how many of the literal's bytes are part of it. `room` is
953            // still consulted because a flexible array member is filled by a literal that keeps
954            // its own type and there is no size in the object for it to be cut to.
955            let ExprKind::Str(id) = tast[value].kind else {
956                self.unsupported("this initializer", span);
957                return None;
958            };
959            let bytes = tast[id].bytes(self.target);
960            let holds = repr::size_of(self.types, self.target, ty);
961            let take = bytes.len().min(cap(holds)).min(cap(room));
962            return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
963        }
964
965        let size = repr::size_of(self.types, self.target, ty);
966        match self.fold(value)? {
967            Const::Int(number) => {
968                let ty = repr::value_type(self.types, self.target, ty)?;
969                // An integer constant of pointer type is a null pointer constant, which is what
970                // `NULL` is, or an address the program wrote as a number. An image is bytes and
971                // `ptr` says nothing about how many, so it goes in as the integer it is at the
972                // width the target's addresses have. An address the linker has to fill in is
973                // the arm below, and is the only one that stays a pointer.
974                let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
975                let imm = self.module.add_imm(Imm::int(number, ty));
976                Some(Datum::Scalar { ty, value: imm })
977            }
978            Const::Float(number) => {
979                let ty = repr::value_type(self.types, self.target, ty)?;
980                let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
981                Some(Datum::Scalar { ty, value: imm })
982            }
983            Const::Address(address) => {
984                let symbol = match address.base {
985                    Base::Decl(decl) => {
986                        // A compound literal is an object nothing declares, so the address of
987                        // one is also the only thing that asks for it to be emitted. Without
988                        // this the image names a symbol the module never defines and the link
989                        // is what finds out. Anything with a name of its own is left alone,
990                        // since the walk over the unit reaches those on its own.
991                        if self.tast[decl].name.is_none() {
992                            self.local_static(decl);
993                        }
994                        self.symbol_of(decl)
995                    }
996                    Base::Str(id) => self.string(id),
997                };
998                let addend = i64::try_from(address.offset).unwrap_or(0);
999                let size = u32::try_from(size).unwrap_or(0);
1000                Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
1001            }
1002        }
1003    }
1004
1005    /// An image of nothing but zeros, which is what a tentative definition has.
1006    fn zeros(&mut self, size: u64) -> DataList {
1007        if size == 0 {
1008            return DataList::EMPTY;
1009        }
1010        self.module.push_data(&[Datum::Zero(size)])
1011    }
1012
1013    /// The global a string literal is emitted as, making it the first time it is asked for.
1014    pub(crate) fn string(&mut self, id: StrId) -> Symbol {
1015        if let Some(&symbol) = self.strings.get(&id) {
1016            return symbol;
1017        }
1018        let literal = &self.tast[id];
1019        let bytes = literal.bytes(self.target);
1020        let align = literal.encoding.element_width(self.target) / 8;
1021        let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
1022
1023        let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
1024        global.linkage = IrLinkage::Internal;
1025        // Not because the type says so, since a literal is an array of `char` and not of
1026        // `const char`, but because writing to one is undefined and every target puts them
1027        // somewhere read-only.
1028        global.constant = true;
1029        let range = self.module.push_bytes(&bytes);
1030        global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
1031        self.module.add_global(global);
1032        self.strings.insert(id, symbol);
1033        symbol
1034    }
1035
1036    /// The name the C library gives a function the program named with the `__builtin_` prefix,
1037    /// and nothing for every other name.
1038    ///
1039    /// `__builtin_abort` is a call to `abort`: the prefix is how a program reaches the function
1040    /// the library promises where a macro or a definition of its own has taken the plain name,
1041    /// so the two spellings are one function and the one the linker will look for is the short
1042    /// one. Which names those are is [`rucc_sema::library_name`]'s to say, since it is the same
1043    /// answer the front end declared them out of.
1044    fn library_name(&mut self, name: Symbol) -> Option<Symbol> {
1045        let library = rucc_sema::library_name(self.names.resolve(name))?;
1046        Some(self.names.intern(library))
1047    }
1048
1049    /// The name an object or a function is known by in the object file.
1050    pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
1051        let tast = self.tast;
1052        let node = &tast[decl];
1053        // The assembler name a declaration wrote, which is the symbol whatever the identifier
1054        // spells. It stands for a `static` and for a local one as well as for a name the linker
1055        // sees, so it is read before anything else here: a program that renames a name has said
1056        // what the symbol is, and the numbering below is for the ones that have not.
1057        if let Some(label) = node.asm_label {
1058            let spelling: String =
1059                tast[label].elements.iter().filter_map(|&unit| char::from_u32(unit)).collect();
1060            return self.names.intern(&spelling);
1061        }
1062        if node.linkage != Linkage::None {
1063            let Some(name) = node.name else { return self.names.intern(".Lanon") };
1064            return self.library_name(name).unwrap_or(name);
1065        }
1066        if let Some(&symbol) = self.statics.get(&decl) {
1067            return symbol;
1068        }
1069        // A `static` in a function, or a compound literal with static storage duration. The
1070        // number is what makes two of them in two functions two objects.
1071        let base = match node.name {
1072            Some(name) => self.names.resolve(name).to_string(),
1073            None => ".Lanon".to_string(),
1074        };
1075        let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
1076        self.statics.insert(decl, symbol);
1077        symbol
1078    }
1079
1080    /// Emits the global for an object with static storage duration declared inside a function.
1081    pub(crate) fn local_static(&mut self, decl: DeclId) {
1082        if !self.done.insert(decl) {
1083            return;
1084        }
1085        match self.tast[decl].kind {
1086            // A function declared inside a body is a declaration of the function, not an
1087            // object with static storage that happens to be one.
1088            DeclKind::Function => self.function(decl),
1089            DeclKind::Object => self.object(decl),
1090        }
1091    }
1092
1093    /// The value of a constant expression, reporting what folding it reported.
1094    fn fold(&mut self, expr: ExprId) -> Option<Const> {
1095        let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
1096        let folded = eval.constant(expr);
1097        let reported = eval.finish();
1098        self.diagnostics.extend(reported);
1099        match folded {
1100            Ok(value) => Some(value),
1101            Err(stop) => {
1102                if !stop.poisoned {
1103                    let span = self.tast.expr_span(stop.at);
1104                    self.unsupported("an initializer this compiler cannot fold", span);
1105                }
1106                None
1107            }
1108        }
1109    }
1110
1111    /// Reports a construct the walk does not build IR for yet.
1112    pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
1113        self.diagnostics.push(
1114            Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1115        );
1116    }
1117
1118    /// Reports a call to a builtin this compiler knows the name of and does nothing with.
1119    ///
1120    /// It is its own message rather than [`Self::unsupported`] because the construct is not the
1121    /// problem: a call is a call, and what is missing is the one function it goes to. The note is
1122    /// what a reader needs, since a builtin is the one name a programmer does not expect to have
1123    /// to provide and the alternative to this message is a linker asking them for it.
1124    pub(crate) fn missing_builtin(&mut self, spelled: &str, span: Span) {
1125        let message = format!("`{spelled}` is not implemented yet");
1126        let note = "a call to it would go to a symbol no object file defines, so this is refused \
1127                    here rather than at the link";
1128        self.diagnostics.push(Diagnostic::error(message, span).with_code("E0686").note(note, span));
1129    }
1130}
1131
1132/// A count of bytes as a length of a slice of them, saturating on a target whose addresses are
1133/// wider than this host's.
1134fn cap(bytes: u64) -> usize {
1135    usize::try_from(bytes).unwrap_or(usize::MAX)
1136}
1137
1138/// The run of bytes a bit-field entry starts, taken out of the map.
1139///
1140/// [`None`] when there is no byte at that offset, which means an earlier entry in the same run
1141/// already took it, since [`Unit::packed`] puts every byte a field lies in into the map.
1142fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
1143    let mut run = vec![bytes.remove(&start)?];
1144    let mut at = start + 1;
1145    while let Some(byte) = bytes.remove(&at) {
1146        run.push(byte);
1147        at += 1;
1148    }
1149    Some(run)
1150}