Skip to main content

rucc_driver/
compile.rs

1//! Running the front end over one file, from the bytes on disk to the typed tree.
2//!
3//! Design: `spec/04-driver-and-cli.md` section 4.3, and the `M2` exit criterion in
4//! `spec/17-milestones.md` that says `--emit=tast` works.
5//!
6//! [`preprocess`](mod@crate::preprocess) stops after phase 4 because `-E` stops there. This
7//! carries on: phase 7, the parse, and the checking. It is one function rather than four composed
8//! ones because of what the four share. The tokens hold interned symbols, the untyped tree holds
9//! tokens, the typed tree holds the untyped tree's spans, and none of them owns the table it is
10//! reading, so one [`Session`] has to outlive all of them and there has to be one place that
11//! holds it.
12
13use std::path::Path;
14
15use rucc_base::Interner;
16use rucc_codegen::coverage::Fired;
17use rucc_codegen::elsewhere::Elsewhere;
18use rucc_codegen::lowering::Lowerings;
19use rucc_codegen::pipeline::{self, Machine, Recording};
20use rucc_codegen::pressure::Pressure;
21use rucc_diag::{Diagnostic, Severity, Span};
22use rucc_ir::{FpContract, Pic as IrPic, Visibility as IrVisibility};
23use rucc_lex::{Convert, Keywords, PpToken, convert};
24use rucc_lower::Protector as LowerProtector;
25use rucc_sema::{Checker, Context as CheckContext};
26use rucc_session::{
27    Contract, EmitKind, FileSystem, Options, Padding, Pic, Protector, Session, Visibility,
28};
29use rucc_target::TargetInfo;
30use rucc_tuple::{Arch, ObjectFormat};
31
32use crate::preprocess::render;
33
34/// What a compilation produced, which is text for most of the kinds and bytes for one of them.
35///
36/// Two variants rather than a string, because an object file is not text and a `Vec<u8>` holding
37/// UTF-8 for six kinds and a file format for the seventh would leave every reader guessing which
38/// it had. [`Artifact::Nothing`] is what a compilation that stopped early gives back, and it is
39/// not the same as an empty file: nothing is written for it at all.
40#[derive(Debug, Clone, PartialEq, Eq, Default)]
41pub enum Artifact {
42    /// The compilation stopped before it produced anything, or the kind asked for produces
43    /// nothing yet.
44    #[default]
45    Nothing,
46    /// Text, which is every kind up to and including assembly.
47    Text(String),
48    /// An object file, which is `-c`, and the names a linker can find in it.
49    ///
50    /// The names travel with the bytes rather than beside them because what wants them is the
51    /// archive step, and an index entry that does not match the member is worse than no archive:
52    /// the linker searches the index, pulls the member out, and still reports the name undefined.
53    /// One value holding both is one value the two cannot disagree in.
54    Object {
55        /// The file.
56        bytes: Vec<u8>,
57        /// Every name another object can reach, as the object writer wrote them. Empty is a real
58        /// answer: a translation unit of nothing but `static` functions is a member an archive
59        /// carries and nothing ever pulls out.
60        defines: Vec<String>,
61    },
62}
63
64impl Artifact {
65    /// The bytes to write, which is nothing at all for [`Artifact::Nothing`].
66    #[must_use]
67    pub fn bytes(&self) -> &[u8] {
68        match self {
69            Artifact::Nothing => &[],
70            Artifact::Text(text) => text.as_bytes(),
71            Artifact::Object { bytes, .. } => bytes,
72        }
73    }
74}
75
76/// What compiling one file produced.
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct Compiled {
79    /// What to write, which is nothing when the compilation failed or produced nothing.
80    pub artifact: Artifact,
81    /// The diagnostics, already rendered, one per element, in the order they were reported.
82    pub messages: Vec<String>,
83    /// How many of them were errors.
84    pub errors: u32,
85    /// Which lowering rules this file fired, for `-Zrule-coverage`.
86    ///
87    /// Empty for a compilation that stopped before the back end, which every kind up to and
88    /// including `--emit=ir` does. That is not the same as a rule set nothing reaches and the
89    /// caller unions these rather than reading one, so a file that fired nothing adds nothing.
90    pub fired: Fired,
91    /// What the register allocator had to put on the stack, for `-Zregister-pressure`.
92    ///
93    /// Empty for the same compilations `fired` is empty for and for the same reason, since both
94    /// are written by the back end and neither is a fact a file that stopped before it has.
95    pub pressure: Pressure,
96    /// What the pre-selection lowering group did, for `-Zlowering`.
97    ///
98    /// Empty for the same compilations `fired` is empty for and for the same reason, since the
99    /// group runs in the back end and a file that stopped before it lowered nothing.
100    pub lowerings: Lowerings,
101    /// What `-fdump-ir=` asked to see, in the order the passes ran.
102    ///
103    /// The optimizer does not write files, because nothing below the driver in
104    /// `spec/18-package-layout.md` knows what a file is, so the text comes back here and the
105    /// caller decides where it goes.
106    pub dumps: Vec<rucc_opt::Dump>,
107    /// What `-fopt-info` asked to hear, already rendered, one remark per line.
108    ///
109    /// Empty when the flag was not given, and also empty when it was given and no pass had
110    /// anything of the kinds asked for to say. Those two are the same text and different facts,
111    /// which is why a misspelled keyword is an error rather than a quiet nothing.
112    pub remarks: String,
113    /// Every file an `#include` found, for the `-M` family.
114    ///
115    /// The same list `Preprocessed` carries and for the same reason. A `-MD` writes it beside
116    /// the object, so the compiling path needs it as much as the preprocessing one does.
117    pub deps: Vec<rucc_pp::Dependency>,
118    /// What `-save-temps` asked to be kept, which is nothing at all unless it was given.
119    ///
120    /// It comes back from here rather than being produced by a second run of the compiler under
121    /// different flags, because a second run is a second answer: the file a person reads has to
122    /// be the file that was compiled, and two runs of anything with a `__TIME__` in it are not
123    /// the same text.
124    pub temps: Temps,
125}
126
127/// The intermediate text a compilation went through, kept when `-save-temps` asked for it.
128///
129/// Both are `None` on a compilation that was not asked to keep anything, and the assembly is
130/// `None` on one that stopped before there was any. Holding the text rather than writing it is
131/// what keeps this function free of the file system, which is what lets it be tested against a
132/// map from path to bytes.
133#[derive(Debug, Clone, PartialEq, Eq, Default)]
134pub struct Temps {
135    /// Phase 4's output, the same text `-E` would have printed.
136    pub preprocessed: Option<String>,
137    /// The assembly the back end produced on the way to the object file.
138    pub assembly: Option<String>,
139}
140
141impl Compiled {
142    /// Whether anything went wrong badly enough that the output should not be used.
143    #[must_use]
144    pub fn failed(&self) -> bool {
145        self.errors > 0
146    }
147
148    /// The text that was produced, and the empty string for anything that is not text.
149    ///
150    /// A caller that asked for one of the text kinds knows which it asked for, so this saves it
151    /// matching on a variant it has already ruled out.
152    #[must_use]
153    pub fn text(&self) -> &str {
154        match &self.artifact {
155            Artifact::Text(text) => text,
156            _ => "",
157        }
158    }
159}
160
161/// Compiles one file as far as `opts.emit` asks for and renders the result.
162///
163/// `name` is the path as the user wrote it, which is the name every diagnostic about the file
164/// uses. Every kind but the executable produces something today, and that one runs the same front
165/// end and gives back nothing, so that a file with a mistake in it is reported the same way
166/// whichever kind was asked for, rather than compiling silently until the part that is written
167/// notices.
168///
169/// The checking is skipped when the parse reported an error. The two poisoning rules mean a
170/// diagnosed expression produces no further complaints, but a declaration the parser had to skip
171/// past leaves no declaration behind at all, and every later use of that name would be reported
172/// as undeclared. One mistake is worth one message.
173#[must_use]
174pub fn compile(opts: &Options, name: &str, fs: &dyn FileSystem) -> Compiled {
175    let mut sess = Session::new(opts.clone());
176    // Before anything else interns a name. The keyword symbols have to be one unbroken run for
177    // a lookup to be a subtraction, and the preprocessor interns every identifier it reads, so
178    // building this after the expansion would mean building it after `char` had been seen.
179    let keywords = Keywords::new(&mut sess.interner, opts.std, opts.gnu_extensions);
180    let mut diagnostics: Vec<Diagnostic> = Vec::new();
181    // Filled in by the back end when there is one, and empty for every kind that stops before it.
182    let mut fired = Fired::new();
183    // The same, and the other thing the back end is asked to record about itself.
184    let mut pressure = Pressure::new();
185    let mut lowerings = Lowerings::asked(opts.lowering_dump.is_some());
186    // Filled in by the optimizer, and only when `-fdump-ir=` asked for something.
187    let mut dumps = Vec::new();
188    let mut remarks = String::new();
189    // Filled in as the compilation goes past each of them, and only under `-save-temps`.
190    let mut temps = Temps::default();
191
192    let bytes = match fs.read(Path::new(name)) {
193        Ok(bytes) => bytes,
194        Err(e) => return failure(format!("{name}: {e}")),
195    };
196    let Ok(file) = sess.sources.add_shared(name, bytes, None) else {
197        return failure(format!("{name}: the source map has no room left for this file"));
198    };
199
200    // Phases 1 to 4. The expanded stream is turned into pp-tokens straight away, because the
201    // include context borrows the source map that rendering a diagnostic reads and the borrow
202    // has to end before anything is rendered.
203    let mut pp = rucc_pp::Preprocessor::with_prefix_map(opts.prefix_map.macros.clone());
204    let predef = rucc_pp::Predef::for_options(opts);
205    let expanded: Vec<PpToken> = {
206        let mut tokens = Vec::new();
207        // The inner block is the borrow. The printer under `-save-temps` reads the source map
208        // that the include context is holding, so the context has to be gone before it runs, and
209        // nothing happens in between, which is what makes the text it prints the text that is
210        // compiled below rather than a second answer to the same question.
211        {
212            let mut cx =
213                rucc_pp::Context::new(&mut sess.interner, &mut sess.sources, fs, &opts.search);
214            cx.lex = rucc_lex::Options::for_dialect(opts.std, opts.gnu_extensions);
215            cx.pedantic = opts.pedantic;
216            if pp.predefine(&sess.target, &predef, &mut cx).is_err() {
217                return failure(format!(
218                    "{name}: the source map has no room for the built in macros"
219                ));
220            }
221            if pp.preinclude(&opts.preincludes, &mut tokens, &mut cx).is_err() {
222                return failure(format!("{name}: the source map has no room for the command line"));
223            }
224            tokens.append(&mut pp.run(file, &mut cx));
225        }
226        if opts.save_temps.wanted() {
227            temps.preprocessed = Some(rucc_pp::print(
228                file,
229                &tokens,
230                pp.line_directives(),
231                &sess.sources,
232                &sess.interner,
233                rucc_pp::PrintOptions { line_markers: opts.line_markers },
234            ));
235        }
236        tokens.iter().map(|token| token.to_pp()).collect()
237    };
238    diagnostics.extend(pp.take_diagnostics());
239    // Taken here rather than at the end, because the preprocessor is done with and everything
240    // after this is about the tree it produced.
241    let deps = pp.dependencies().to_vec();
242
243    // Phase 7, which is where a spelling becomes a keyword and a preprocessing number becomes
244    // a constant of a type.
245    let cx = Convert {
246        keywords: &keywords,
247        interner: &sess.interner,
248        target: &sess.target,
249        std: opts.std,
250        gnu: opts.gnu_extensions,
251        pedantic: opts.pedantic,
252    };
253    let (tokens, complaints) = convert(&expanded, &cx);
254    diagnostics.extend(complaints);
255
256    let parsed = rucc_parse::parse(
257        &tokens,
258        rucc_parse::Context {
259            interner: &sess.interner,
260            std: opts.std,
261            gnu: opts.gnu_extensions,
262            pedantic: opts.pedantic,
263            error_limit: opts.error_limit as usize,
264        },
265    );
266    let parse_failed = parsed.diagnostics.iter().any(|d| d.severity.is_fatal());
267    diagnostics.extend(parsed.diagnostics);
268
269    let mut artifact = Artifact::Nothing;
270    // Zero when nothing instruments, which is the truthful summary of a file built without
271    // `-fsafety`: no checks went in, so none is standing, and every call it makes is unmodelled.
272    let mut instrumented = Instrumented::default();
273    if !parse_failed {
274        let mut checker = Checker::new(
275            &parsed.ast,
276            CheckContext {
277                names: &sess.interner,
278                target: &sess.target,
279                std: opts.std,
280                gnu: opts.gnu_extensions,
281                pedantic: opts.pedantic,
282                permissive: opts.permissive,
283                gnu89_inline: opts.gnu89_inline,
284                error_limit: opts.error_limit as usize,
285                // A freestanding program has no C library, so a name that is the library's
286                // everywhere else is the program's own here and means whatever it defined.
287                builtins: opts.builtins && opts.hosted,
288                no_builtin: &opts.no_builtin,
289                short_enums: opts.short_enums,
290                ms_extensions: sess.ms_extensions(),
291                trapping_math: opts.trapping_math,
292            },
293        );
294        checker.check_unit();
295        let checked = checker.finish();
296        if !checked.failed() {
297            match opts.emit {
298                EmitKind::Tast => {
299                    artifact = Artifact::Text(rucc_sema::print(
300                        &checked.tast,
301                        &checked.types,
302                        &sess.interner,
303                    ));
304                }
305                // Nothing past the checker, because a granule is a fact about a layout and a
306                // layout is settled the moment the closing brace is seen. Lowering the
307                // function bodies would take minutes on an amalgamation and answer nothing.
308                EmitKind::TypeGranules => {
309                    artifact = Artifact::Text(rucc_types::granule_report(
310                        &checked.types,
311                        &sess.interner,
312                        &sess.target,
313                    ));
314                }
315                EmitKind::Ir
316                | EmitKind::MirFinal
317                | EmitKind::Asm
318                | EmitKind::Object
319                | EmitKind::Archive
320                | EmitKind::Executable
321                | EmitKind::SafetySummary => {
322                    // What a `.incbin` in an `asm` at file scope names is read through the same
323                    // file system the sources came through, and from where the compiler was run
324                    // rather than from beside the source, because that is where an assembler
325                    // looks for it.
326                    let mut read = |named: &str| {
327                        fs.read(Path::new(named))
328                            .map(|bytes| bytes.as_slice().to_vec())
329                            .map_err(|why| why.to_string())
330                    };
331                    let mut lowered = rucc_lower::lower(
332                        name,
333                        rucc_lower::Context {
334                            tast: &checked.tast,
335                            types: &checked.types,
336                            target: &sess.target,
337                            names: &mut sess.interner,
338                            visibility: match opts.visibility {
339                                Visibility::Default => IrVisibility::Default,
340                                Visibility::Hidden => IrVisibility::Hidden,
341                                Visibility::Protected => IrVisibility::Protected,
342                            },
343                            protector: match opts.protector {
344                                Protector::None => LowerProtector::None,
345                                Protector::Buffers => LowerProtector::Buffers,
346                                Protector::Strong => LowerProtector::Strong,
347                                Protector::All => LowerProtector::All,
348                            },
349                            wrapping: rucc_lower::Wrapping {
350                                signed: opts.wrapping.signed,
351                                pointer: opts.wrapping.pointer,
352                                trap: opts.wrapping.trap,
353                            },
354                            aliasing: opts.strict_aliasing,
355                            padding: opts.padding == Padding::Ignored,
356                            contract: match opts.fp_contract {
357                                Contract::Off => FpContract::Off,
358                                Contract::On => FpContract::On,
359                                Contract::Fast => FpContract::Fast,
360                            },
361                            read: &mut read,
362                        },
363                    );
364                    // The walk reports what it cannot build, and what it did build is printed
365                    // anyway: a file with one construct missing from it is more use to read
366                    // than nothing at all, and the errors are what stop it being compiled.
367                    let failed = lowered.diagnostics.iter().any(|d| d.severity.is_fatal());
368                    if !failed {
369                        // The verifier runs on everything the walk builds, always. It is the
370                        // one check that a bug in the walk cannot talk its way past, and a
371                        // wrong instruction found here costs a message rather than an hour
372                        // in front of a debugger over the assembly it turned into.
373                        if let Err(errors) = rucc_ir::verify(&lowered.module, &sess.interner) {
374                            for error in errors {
375                                diagnostics.push(internal(&format!("invalid IR, {error}")));
376                            }
377                        } else if let Err(complaints) =
378                            instrument(&mut lowered.module, &mut sess.interner, opts)
379                                .map(|done| instrumented = done)
380                        {
381                            diagnostics.extend(complaints);
382                        } else if let Err(complaints) = optimize(
383                            &mut lowered.module,
384                            &sess.interner,
385                            &sess.target,
386                            opts,
387                            name,
388                            &mut dumps,
389                            &mut remarks,
390                        ) {
391                            diagnostics.extend(complaints);
392                        } else if opts.emit == EmitKind::SafetySummary {
393                            // After the optimizer, because the number that matters is how many
394                            // checks are still standing and there is no way to know that before it
395                            // has run. Before the back end, because the back end turns a check into
396                            // a call and a summary of calls is not a summary of checks.
397                            artifact = Artifact::Text(
398                                rucc_safety::summarize(
399                                    &lowered.module,
400                                    &sess.interner,
401                                    name,
402                                    opts.safety.as_str(),
403                                    instrumented.checks,
404                                    instrumented.interposed,
405                                    instrumented.crossings,
406                                )
407                                .render(),
408                            );
409                        } else if opts.emit == EmitKind::Ir {
410                            // After the optimizer rather than before it, so that `--emit=ir -O2`
411                            // is the IR the back end will be given rather than the IR it would
412                            // have been given at `-O0`. There is no other way to see what a pass
413                            // did without reading the assembly it turned into.
414                            artifact =
415                                Artifact::Text(rucc_ir::print(&lowered.module, &sess.interner));
416                        } else {
417                            // The back end, which is every pass after the IR and which is
418                            // where a construct nothing has a rule for is finally noticed.
419                            match generate(
420                                &mut lowered.module,
421                                &mut sess.interner,
422                                &sess.target,
423                                opts,
424                                &mut Recording {
425                                    fired: &mut fired,
426                                    pressure: &mut pressure,
427                                    lowerings: &mut lowerings,
428                                },
429                                &mut temps.assembly,
430                            ) {
431                                Ok(made) => artifact = made,
432                                Err(complaints) => diagnostics.extend(complaints),
433                            }
434                        }
435                    }
436                    diagnostics.extend(lowered.diagnostics);
437                }
438                _ => {}
439            }
440        }
441        diagnostics.extend(checked.diagnostics);
442    }
443
444    let mut messages = Vec::with_capacity(diagnostics.len());
445    let mut errors = 0;
446    for diag in &diagnostics {
447        // `-w` drops the warning here rather than at the several hundred places one is raised,
448        // and it drops it before the count, so `-w -Werror` compiles. A warning that was never
449        // raised is not a warning there is anything to promote.
450        if !opts.warnings && diag.severity == Severity::Warning {
451            continue;
452        }
453        if diag.severity.is_fatal()
454            || (diag.severity == Severity::Warning && opts.warnings_are_errors)
455        {
456            errors += 1;
457        }
458        messages.push(render(diag, &sess.sources, opts.warnings_are_errors));
459    }
460    if errors > 0 {
461        // A tree built from a file that did not compile is not a tree anything should read.
462        artifact = Artifact::Nothing;
463    }
464    // Kept even when the compilation failed, because a rule that fired did fire and a report about
465    // which rules a corpus reaches should not lose the ones a file with a mistake in it reached.
466    Compiled { artifact, messages, errors, fired, pressure, lowerings, dumps, remarks, deps, temps }
467}
468
469/// Reads one file of IR, checks it, and prints it back.
470///
471/// This is the compiler's own textual IR arriving as an input rather than leaving as an output,
472/// which is what makes the round trip in the M2 exit criterion something to run rather than
473/// something to believe: what the printer wrote is read back, verified, and written again, and
474/// the two files are either the same bytes or they are not.
475///
476/// The verifier runs here for the reason it runs after the walk. A module that was printed by
477/// this compiler has been through it once already, and one that a person edited has not.
478#[must_use]
479pub fn compile_ir(opts: &Options, name: &str, fs: &dyn FileSystem) -> Compiled {
480    let mut sess = Session::new(opts.clone());
481    if opts.emit != EmitKind::Ir {
482        return failure(format!(
483            "{name}: an input of IR can only be emitted as IR, and `--emit={}` asks for what \
484             the C in front of it became",
485            opts.emit.as_str()
486        ));
487    }
488    let bytes = match fs.read(Path::new(name)) {
489        Ok(bytes) => bytes,
490        Err(e) => return failure(format!("{name}: {e}")),
491    };
492    let Ok(text) = std::str::from_utf8(bytes.as_slice()) else {
493        return failure(format!("{name}: this is not text, so it is not IR"));
494    };
495
496    let module = match rucc_ir::parse(text, &mut sess.interner) {
497        Ok(module) => module,
498        Err(error) => {
499            return failure(format!("{name}:{}: {}", error.line, error.message));
500        }
501    };
502    let mut diagnostics: Vec<Diagnostic> = Vec::new();
503    if let Err(errors) = rucc_ir::verify(&module, &sess.interner) {
504        for error in errors {
505            diagnostics.push(invalid(&format!("invalid IR, {error}")));
506        }
507    }
508    let mut messages = Vec::with_capacity(diagnostics.len());
509    for diag in &diagnostics {
510        messages.push(render(diag, &sess.sources, opts.warnings_are_errors));
511    }
512    let errors = u32::try_from(messages.len()).unwrap_or(u32::MAX);
513    let artifact = if errors > 0 {
514        Artifact::Nothing
515    } else {
516        Artifact::Text(rucc_ir::print(&module, &sess.interner))
517    };
518    // Nothing here reaches the back end, so no rule fired and there is nothing to record.
519    Compiled {
520        artifact,
521        messages,
522        errors,
523        fired: Fired::new(),
524        pressure: Pressure::new(),
525        lowerings: Lowerings::new(),
526        dumps: Vec::new(),
527        remarks: String::new(),
528        deps: Vec::new(),
529        temps: Temps::default(),
530    }
531}
532
533/// Puts the memory safety checks in and redirects the calls that cross the boundary, when
534/// `-fsafety=` asked for them.
535///
536/// Between the walk and the optimizer, which is where section 15.3 of
537/// `spec/safe-memory/15-integration.md` puts it and which is the whole design in one line: the
538/// checks go in while the addresses the program computes still exist, and the optimizer then
539/// discharges the ones it can prove. Every sanitizer that came before instruments after the
540/// optimizer so that its checks cannot be deleted, and pays for all of them forever.
541///
542/// The calls to the C library are redirected here too, and in the same window and for a related
543/// reason. `spec/safe-memory/10-boundaries.md` section 10.3 wants a `memcpy` modelled by a wrapper
544/// that performs the judgements, and `rucc_safety::wrap` is why that has to happen before the
545/// optimizer sees the call rather than after.
546///
547/// The verifier runs again afterwards, for the reason it runs after the walk. This pass rewrites
548/// every function in the module, and a pass that produced IR nothing else accepts should say so
549/// here rather than in the assembly it turned into.
550///
551/// # Errors
552///
553/// When the inserted checks left the module in a state the verifier refuses, which is a bug in
554/// this compiler and not in the program being compiled.
555fn instrument(
556    module: &mut rucc_ir::Module,
557    names: &mut Interner,
558    opts: &Options,
559) -> Result<Instrumented, Vec<Diagnostic>> {
560    if !opts.safety.instruments() {
561        return Ok(Instrumented::default());
562    }
563    let mut checks = rucc_safety::run(module, opts.subobject, opts.promise, opts.races);
564    // The one check that is about a call rather than about an access, so it is a walk of its own
565    // and it is here rather than in the walk above. `rucc_safety::ending` is why, and the short
566    // version is that deciding it means resolving a name, which takes the interner.
567    //
568    // Before the redirection for the same reason the redirection is before the optimizer: what this
569    // reads is the name the program wrote, and a pass that had already pointed the call somewhere
570    // else would leave it with a name this one has no row for.
571    checks.freed = rucc_safety::ending::checks(module, names);
572    // Before the optimizer rather than beside the check lowering, which is what
573    // `rucc_safety::wrap` argues out: `memcpy` is a name an optimizer knows things about, and a
574    // pass that turns a short copy into a pair of loads and stores would leave behind accesses the
575    // check insertion has already finished walking past.
576    let interposed = rucc_safety::redirect(module, names);
577    // After the redirection, so that a call this build models with a wrapper is not also counted
578    // as a crossing it did not model.
579    let crossings = rucc_safety::witness(module, names);
580    match rucc_ir::verify(module, names) {
581        Ok(()) => Ok(Instrumented { checks, interposed, crossings }),
582        Err(errors) => Err(errors
583            .iter()
584            .map(|e| internal(&format!("invalid IR after check insertion, {e}")))
585            .collect()),
586    }
587}
588
589/// What the instrumentation did, which nothing but the summary reads.
590///
591/// Carried out of [`instrument`] rather than recovered from the module afterwards because neither
592/// number survives the optimizer: a check that was discharged leaves nothing behind saying it was
593/// ever there, and a call that was pointed at a wrapper looks like a call that always named one.
594#[derive(Clone, Copy, Debug, Default)]
595struct Instrumented {
596    /// How many checks of each class went in.
597    checks: rucc_safety::Counts,
598    /// How many calls were pointed at an interposition wrapper.
599    interposed: usize,
600    /// How many places a pointer crosses to or from code this build did not instrument.
601    crossings: rucc_safety::Sites,
602}
603
604/// Runs the optimizer over the module, and collects whatever the dumps asked for.
605///
606/// The level chooses a pipeline, the `-f` flags edit it, and at `-O0` there is nothing in it, so
607/// this is a walk over an empty list rather than a branch on the level. See section 9.1 of
608/// `spec/09-optimizer.md` for why the pipelines are written out rather than assembled.
609///
610/// # Errors
611///
612/// When a pass left the module in a state the verifier refuses, which is a bug in the pass and
613/// not in the program being compiled, so it is reported as an internal error the way a bad
614/// lowering is.
615fn optimize(
616    module: &mut rucc_ir::Module,
617    names: &Interner,
618    target: &TargetInfo,
619    opts: &Options,
620    file: &str,
621    dumps: &mut Vec<rucc_opt::Dump>,
622    remarks: &mut String,
623) -> Result<(), Vec<Diagnostic>> {
624    let mut settings = rucc_opt::Options::for_level(opts.opt_level);
625    // What the analyses that read a body may believe about it. The same question the back end asks
626    // about addresses, with one thing on top: `-fno-semantic-interposition` is the build promising
627    // that a name it exports is the one that will run, which is what every distribution builds a
628    // library with. It says nothing about how an address is reached, and gcc does not change that
629    // under the flag either, so the back end is not given this value.
630    settings.interposition = match opts.interposition {
631        true => replaceable(target, opts),
632        false => IrPic::Executable,
633    };
634    settings.toggles.clone_from(&opts.passes);
635    settings.fuel = opts.pass_fuel.iter().cloned().collect();
636    settings.global_fuel = opts.pass_fuel_global;
637    settings.verify |= opts.verify_each;
638    for (on, spec) in &opts.pass_gates {
639        // Same argument as the dumps below: every spelling in here was checked while the
640        // arguments were parsed, so a rejection now is this compiler disagreeing with itself.
641        if let Err(why) = settings.gates.add(*on, spec) {
642            return Err(vec![internal(&why)]);
643        }
644    }
645    for spec in &opts.dump_ir {
646        // Every spelling in here was checked while the arguments were parsed, so a rejection
647        // now is this compiler disagreeing with itself rather than the command line being wrong.
648        if let Err(why) = settings.dumps.add(spec) {
649            return Err(vec![internal(&why)]);
650        }
651    }
652    let mut wants = rucc_opt::Wants::none();
653    for spec in &opts.opt_info {
654        // Same argument as the dumps above: every spelling was checked while the arguments were
655        // parsed, so a rejection now is the compiler disagreeing with itself.
656        if let Err(why) = wants.add(spec) {
657            return Err(vec![internal(&why)]);
658        }
659    }
660    let report = rucc_opt::run(module, names, &settings);
661    remarks.push_str(&rucc_opt::optinfo::render(file, &report, names, wants));
662    dumps.extend(report.dumps);
663    match report.broke.is_empty() {
664        true => Ok(()),
665        false => Err(report.broke.iter().map(|why| internal(why)).collect()),
666    }
667}
668
669/// Runs the back end over every function in `module` and writes what came out.
670///
671/// One machine function per definition in the module, in the order the module holds them, every
672/// register physical and every frame offset a constant. A declaration has no body and is skipped,
673/// because there is nothing in it to compile.
674///
675/// What the last step is, is the only thing `--emit=mir-final`, `-S` and `-c` disagree about. The
676/// three read the same functions and differ in whether they are printed as machine IR, printed as
677/// assembly, or encoded and put in a file, which is the point of section 11.1 of
678/// `spec/11-asm-objects-debug.md`: a listing that disagrees with the object file beside it is
679/// worse than no listing, and the way to make that impossible is to have one description of an
680/// instruction and two ways of writing it down.
681///
682/// # Errors
683///
684/// One diagnostic per function the back end could not compile, or one about the target when no
685/// back end covers it at all. Every function is attempted rather than stopping at the first, so a
686/// file with three constructs missing from the rule set reports three rather than one at a time.
687///
688/// `assembly` is where `-save-temps` gets its listing from on the path that does not print one,
689/// which is the same functions written the other way rather than a second compilation of the same
690/// file. A listing that disagrees with the object beside it would be worse than none.
691/// Whether a name this file exports is one another object may define or replace.
692///
693/// The link that reads the object decides half of what is in it, and the command line is where that
694/// is said, which is why the flag reaches this far down. See #756.
695///
696/// ELF only, because it is a question about a format rather than about a machine and the other two
697/// answer it differently. Mach-O has a two level namespace, so a name a library defines is bound to
698/// that library and is not replaced by a definition loaded earlier, and it has no copy relocations,
699/// so a variable defined elsewhere needs the table whichever link is coming. COFF decides what
700/// leaves a DLL by an export table the linker is handed. Neither has an object writer here yet, so
701/// what this does is decline to say the ELF answer about them.
702fn replaceable(target: &TargetInfo, opts: &Options) -> IrPic {
703    match (target.tuple.os().object_format(), opts.pic) {
704        (Some(ObjectFormat::Elf), Pic::Library) => IrPic::Library,
705        _ => IrPic::Executable,
706    }
707}
708
709fn generate(
710    module: &mut rucc_ir::Module,
711    names: &mut Interner,
712    target: &TargetInfo,
713    opts: &Options,
714    recording: &mut Recording<'_>,
715    assembly: &mut Option<String>,
716) -> Result<Artifact, Vec<Diagnostic>> {
717    let Some(machine) = Machine::for_target(target) else {
718        return Err(vec![unsupported(&format!(
719            "there is no back end for {} in this compiler yet, so there is nothing to generate",
720            target.tuple
721        ))]);
722    };
723    // Refused rather than dropped. A command line that asks for a stack protector on a target
724    // that has nowhere to keep the word one is compared against would otherwise get code with no
725    // protection in it and no indication that the flag did nothing, which is the one outcome worse
726    // than the error. Windows is the case: it has a protector and it is a different mechanism.
727    if opts.protector != Protector::None && machine.conv.guard.is_none() {
728        return Err(vec![unsupported(&format!(
729            "{} is not supported for {} yet, because the stack protector on that target is not \
730             the one this compiler writes",
731            opts.protector, target.tuple
732        ))]);
733    }
734    // The same answer for the same reason. What says a file was built to have its control flow
735    // checked is a note, the note is an ELF one, and a target whose objects are not ELF has nowhere
736    // to put it: the landing pads would go in and nothing would ever turn the check on. Windows has
737    // the same hardware and asks for it a different way, which is a bit in the image the linker is
738    // told to set rather than anything a compiler writes into an object.
739    if opts.control.any() && target.tuple.os().object_format() != Some(ObjectFormat::Elf) {
740        return Err(vec![unsupported(&format!(
741            "-fcf-protection={} is not supported for {} yet, because what says a file was built \
742             for it there is not the note this compiler writes",
743            opts.control, target.tuple
744        ))]);
745    }
746    // And once more. A profiled build is one whose functions call a routine the runtime provides,
747    // and a target whose runtime provides no such routine would get a call to a name nothing
748    // defines, which is a link error a long way from the flag that caused it. Windows profiles a
749    // build by calling something else, asked for a different way and taking its argument in a
750    // register, so it is not this hook spelled differently.
751    let profile = match machine.conv.trace {
752        Some(trace) => opts.profile.then(|| opts.hook.early(trace.fentry)),
753        None if opts.profile => {
754            return Err(vec![unsupported(&format!(
755                "-pg is not supported for {} yet, because the profiler's hook on that target is \
756                 not the one this compiler calls",
757                target.tuple
758            ))]);
759        }
760        None => None,
761    };
762    // And once more. The room a patcher was promised is only half the feature: the other half is a
763    // section listing where every function's room is, and both the section's shape and the way it
764    // points at the text it belongs to are ELF's. A format that has no such section would take the
765    // nops and quietly lose the list, which is a build that looks patchable and is not.
766    if opts.patchable.any() && target.tuple.os().object_format() != Some(ObjectFormat::Elf) {
767        return Err(vec![unsupported(&format!(
768            "-fpatchable-function-entry= is not supported for {} yet, because what records where \
769             the room is there is not the section this compiler writes",
770            target.tuple
771        ))]);
772    }
773    let flags = pipeline::Flags {
774        frame_pointer: opts.frame_pointer,
775        red_zone: opts.red_zone,
776        stack_clash: opts.stack_clash,
777        landing: opts.control.branch(),
778        profile: match profile {
779            None => pipeline::Profile::No,
780            Some(true) => pipeline::Profile::Early,
781            Some(false) => pipeline::Profile::Late,
782        },
783        patch: pipeline::Room { after: opts.patchable.after(), before: opts.patchable.before },
784        // On at every level above `-O0`, which is where gcc turns `-freorder-blocks` on
785        // (`gcc/opts.cc:604`) and what `spec/optimizer/38-scheduling-and-layout.md` section 38.3
786        // reads off that: it is one of the earliest optimizations there is, it is nearly free,
787        // and it helps every target. `-O0` keeps the order the shape of the graph gives, so that
788        // the blocks come out in the order they were written and a person stepping through the
789        // code walks down the screen.
790        reorder: opts.reorder_blocks.unwrap_or_else(|| opts.opt_level.runs_optimizer()),
791        // On at every level above `-O0`, for the reason the line above is off at it. Sharing one
792        // run of bytes between two locals is a smaller frame and a worse debugger: a variable that
793        // is out of scope reads as whatever took its place, which is what `-O0` exists not to do.
794        // Above it the frame is the win, and `-fstack-reuse=` says either answer at any level.
795        reuse: opts.stack_reuse.unwrap_or_else(|| opts.opt_level.runs_optimizer()),
796        // On from `-O2`, which is where gcc turns `-fschedule-insns2` on and what
797        // `spec/optimizer/38-scheduling-and-layout.md` section 38.6 asks for. Not at `-O1`,
798        // because a schedule is a whole dependence graph per block and `-O1` is the level whose
799        // budget is roughly `-O0`'s. Not at `-O0` for the reason nothing else is.
800        schedule: opts.schedule_insns.unwrap_or_else(|| opts.opt_level.schedules()),
801        // Whatever the command line said, and the model's own answer when it said nothing.
802        accurate: opts.cycle_accurate_model,
803    };
804
805    // The checks become calls here rather than beside the insertion, because the id each one
806    // carries is an index into a table and a row for a check the optimizer deleted is a row nothing
807    // will ever name. Section 6.3.1 of `spec/safe-memory/06-instrumentation.md` is what this
808    // eventually becomes and `rucc_safety::lower` says why it is not that yet.
809    //
810    // It is inside the back end rather than beside the optimizer so that `--emit=ir` still shows
811    // the checks. The IR a person reads should say what the compiler decided, not how it spelled it
812    // for the machine.
813    if opts.safety.instruments() {
814        // Which calls hand back storage, which the lowering needs and `-O0` has not worked out.
815        // `rucc_opt::pipeline` runs this only when some pass in the run reads the summaries, since a
816        // flag nothing reads is noise in a dump, and at `-O0` nothing did. Something does now: the
817        // capability for a pointer an allocator just returned is the one capability that is exact
818        // and costs a load, and `rucc_safety::slot` finds those sites by the flag. The safety suite
819        // runs at `-O0`, so without this the cheap case would be the one case that never happens.
820        //
821        // Safe to run twice and safe to run late, because it only ever sets the flag and never
822        // clears one, so a build that had it already gets the same module back.
823        rucc_opt::heap::annotate(module, names);
824        // Which calls hand their capabilities to the callee and which say there are none. Here and
825        // not beside the insertion, because the rule is what each function still has left to check
826        // and the optimizer is what makes that small: running before it would give every callee a
827        // frame for checks that are about to be discharged. `rucc_safety::handover` is the rule and
828        // the pass both, and the census in `--emit=safety-summary` reads the same rule, so the
829        // buckets it prints describe the code that was actually built.
830        rucc_safety::handover::arrange(module);
831        rucc_safety::lower(module, names);
832        if let Err(errors) = rucc_ir::verify(module, names) {
833            return Err(errors
834                .iter()
835                .map(|e| internal(&format!("invalid IR after check lowering, {e}")))
836                .collect());
837        }
838    }
839
840    // Worked out before the loop and not inside it, because it reads the whole module and the loop
841    // is holding one function of it. It has to be after the check lowering above, since that adds
842    // calls to the runtime and so can add a name this file does not define.
843    //
844    // The link that reads the object decides half of what is in it, and the command line is where
845    // that is said, which is why the flag reaches this far down. See #756.
846    //
847    let elsewhere = Elsewhere::of(module, replaceable(target, opts));
848
849    let mut funcs = Vec::new();
850    let mut complaints = Vec::new();
851    for id in module.funcs() {
852        if module[id].is_declaration() {
853            continue;
854        }
855        match pipeline::compile_recording(
856            &mut module[id],
857            names,
858            &machine,
859            &elsewhere,
860            flags,
861            recording,
862        ) {
863            Ok(func) => funcs.push(func),
864            Err(why) => {
865                let name = names.resolve(module[id].name).to_owned();
866                // The function knows where the instruction came from, so the message lands on
867                // the line somebody wrote rather than on the file as a whole.
868                let span = why.inst().map_or(Span::DUMMY, |inst| module[id].span(inst));
869                let said = format!("cannot generate code for '{name}': {why}");
870                complaints.push(unsupported_at(&said, span));
871            }
872        }
873    }
874    if !complaints.is_empty() {
875        return Err(complaints);
876    }
877    // The variables the file defines, which go through the back end the way the functions did not:
878    // there is nothing in a variable to select instructions for, so the module is what says what
879    // one is right up to the point where it is written down.
880    // The second names go the same way and for the same reason, and they are neither a function
881    // nor a variable: an alias is an entry in the symbol table and no bytes of anything.
882    let (globals, aliases) = match opts.emit {
883        EmitKind::Asm | EmitKind::Object | EmitKind::Archive | EmitKind::Executable => (
884            rucc_asm::globals(module, names, target.object_format).map_err(refused)?,
885            rucc_asm::aliases(module, names).map_err(refused)?,
886        ),
887        _ => (rucc_asm::Globals::default(), Vec::new()),
888    };
889    // A failure in either of the last two is a bug here rather than a program this compiler is
890    // behind on, because every instruction in a function that got this far came out of the same
891    // description both of them read and every register in it has been allocated.
892    let unwind = opts.unwinds();
893    match opts.emit {
894        EmitKind::Asm => {
895            rucc_asm::print(&funcs, &globals, &aliases, names, target, unwind, output(opts, target))
896                .map(Artifact::Text)
897                .map_err(refused)
898        }
899        // An executable is an object as far as this gets: one is what each file of a link
900        // contributes, and the linker is what turns them into the other. An archive is the same
901        // again, with the archive writer in place of the linker.
902        EmitKind::Object | EmitKind::Archive | EmitKind::Executable => {
903            if opts.save_temps.wanted() {
904                let listing = rucc_asm::print(
905                    &funcs,
906                    &globals,
907                    &aliases,
908                    names,
909                    target,
910                    unwind,
911                    output(opts, target),
912                );
913                *assembly = Some(listing.map_err(refused)?);
914            }
915            let text = rucc_asm::assemble(&funcs, names, target, unwind).map_err(refused)?;
916            let data = globals.image();
917            // A format with no writer is a target this compiler is behind on and anything else
918            // the writer refused is a bug here, and the two are not the same news to get.
919            let bytes = rucc_object::write(&text, &data, &aliases, target, output(opts, target))
920                .map_err(wrote)?;
921            // Asked of the writer rather than worked out from the same three values here, so that
922            // what the archive's index says and what is in the member cannot come apart. It is
923            // wanted only by `--emit=archive` and is cheap enough that the other two kinds are not
924            // worth a second path.
925            let defines = rucc_object::defines(&text, &data, &aliases, target).map_err(wrote)?;
926            Ok(Artifact::Object { bytes, defines })
927        }
928        _ => Ok(Artifact::Text(rucc_mir::print(&funcs, names, target.regs))),
929    }
930}
931
932/// What the command line decided about the file being written, in the words the assembler and the
933/// object writer use.
934///
935/// Two spellings of the same facts, because the flags are the command line's and the answer the two
936/// writers want is the object format's. The conversion is here rather than in either of them so
937/// that the two output paths are handed the same thing and cannot come to disagree about what is
938/// in a file.
939///
940/// The feature word is empty on a machine whose bits these are not. It is the x86 one, and a target
941/// that wanted its control flow checked would want a property of its own with a key of its own, so
942/// writing this one there would be recording something untrue rather than recording nothing.
943fn output(opts: &Options, target: &TargetInfo) -> rucc_object::Output {
944    let mut features = 0;
945    if target.tuple.arch() == Arch::X86_64 {
946        if opts.control.branch() {
947            features |= rucc_object::Property::IBT;
948        }
949        if opts.control.ret() {
950            features |= rucc_object::Property::SHSTK;
951        }
952    }
953    rucc_object::Output {
954        sections: rucc_object::Sections {
955            functions: opts.function_sections,
956            data: opts.data_sections,
957        },
958        property: rucc_object::Property { features },
959    }
960}
961
962/// What the object writer said, as the kind of news it is.
963///
964/// A format with no writer is a target this compiler is behind on, which is a program nobody can
965/// compile today and not a mistake in the one being compiled. Anything else it refused is a bug
966/// here, because every value it was handed came out of this compiler.
967fn wrote(why: rucc_object::Error) -> Vec<Diagnostic> {
968    match why {
969        rucc_object::Error::Format { .. } => vec![unsupported(&why.to_string())],
970        rucc_object::Error::Refused { .. } => vec![internal(&why.to_string())],
971    }
972}
973
974/// What the assembler said, as the kind of news it is.
975///
976/// Three of these are about a program and the rest are about this compiler. A thread-local
977/// variable, an ifunc and a prologue the target's unwind table cannot describe are all valid C that
978/// the back end does not build yet, and everything else the assembler refuses is something that
979/// should never have reached it.
980fn refused(why: rucc_asm::Error) -> Vec<Diagnostic> {
981    match why {
982        rucc_asm::Error::Thread { .. }
983        | rucc_asm::Error::IFunc { .. }
984        | rucc_asm::Error::Frame { .. } => {
985            vec![unsupported(&why.to_string())]
986        }
987        _ => vec![internal(&why.to_string())],
988    }
989}
990
991/// A diagnostic about a program this compiler is not finished enough to compile.
992///
993/// Not an internal error, because nothing here is wrong: the program is valid C and the part of
994/// the back end that would handle it has not been written. The note says so, so that a report
995/// about one of these is filed against the milestone rather than as a miscompilation.
996fn unsupported(message: &str) -> Diagnostic {
997    unsupported_at(message, Span::DUMMY)
998}
999
1000/// The same, about somewhere in the file rather than about the file.
1001///
1002/// The note names the issue tracker rather than `spec/17-milestones.md`, which is a document
1003/// about the plan: a reader who follows it wants to know whether the construct in front of them
1004/// is already written down as work, and the milestone list does not answer that.
1005fn unsupported_at(message: &str, span: Span) -> Diagnostic {
1006    Diagnostic::error(message.to_owned(), span)
1007        .with_code("E0653")
1008        .note("this construct is not lowered yet, see https://github.com/tamnd/rucc/issues", span)
1009}
1010
1011/// A diagnostic about IR that was handed to us rather than built by us.
1012fn invalid(message: &str) -> Diagnostic {
1013    Diagnostic::error(message.to_owned(), Span::DUMMY).with_code("E0661")
1014}
1015
1016/// A diagnostic about this compiler rather than about the program it was given.
1017fn internal(message: &str) -> Diagnostic {
1018    Diagnostic::error(format!("internal error: {message}"), Span::DUMMY)
1019        .with_code("E0652")
1020        .note("this is a bug in rucc rather than in the program, please report it", Span::DUMMY)
1021}
1022
1023/// A result that is nothing but one message, for the failures that happen before there is
1024/// anything to compile.
1025fn failure(message: String) -> Compiled {
1026    Compiled {
1027        artifact: Artifact::Nothing,
1028        messages: vec![format!("rucc: error: {message}")],
1029        errors: 1,
1030        fired: Fired::new(),
1031        pressure: Pressure::new(),
1032        lowerings: Lowerings::new(),
1033        dumps: Vec::new(),
1034        remarks: String::new(),
1035        deps: Vec::new(),
1036        temps: Temps::default(),
1037    }
1038}
1039
1040#[cfg(test)]
1041mod tests {
1042    use rucc_session::{MemoryFileSystem, Std};
1043    use rucc_target::Triple;
1044
1045    use super::*;
1046
1047    fn options() -> Options {
1048        let mut opts = Options::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
1049        opts.emit = EmitKind::Tast;
1050        opts
1051    }
1052
1053    fn run(opts: &Options, source: &str) -> Compiled {
1054        let mut fs = MemoryFileSystem::new();
1055        fs.insert("/main.c", source.to_owned().into_bytes());
1056        compile(opts, "/main.c", &fs)
1057    }
1058
1059    /// Options with the compiler's own headers on the search path and nothing else, which is
1060    /// what a freestanding compilation is. There is no file system underneath these tests,
1061    /// so a header that reached for one would fail to resolve and say so.
1062    fn freestanding() -> Options {
1063        let mut opts = options();
1064        opts.hosted = false;
1065        opts.search.push_system(rucc_session::runtime::DIR);
1066        opts
1067    }
1068
1069    /// The typed tree of a freestanding `source`, insisting that it compiled cleanly.
1070    fn shipped(source: &str) -> String {
1071        let result = run(&freestanding(), source);
1072        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
1073        result.text().to_owned()
1074    }
1075
1076    /// The typed tree of `source`, insisting that it compiled cleanly.
1077    fn tast(source: &str) -> String {
1078        let result = run(&options(), source);
1079        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
1080        result.text().to_owned()
1081    }
1082
1083    #[test]
1084    fn the_shipped_stdarg_declares_a_list_and_the_four_operators() {
1085        let text = shipped(concat!(
1086            "#include <stdarg.h>\n",
1087            "int sum(int n, ...) {\n",
1088            "  va_list ap, copy;\n",
1089            "  va_start(ap, n);\n",
1090            "  va_copy(copy, ap);\n",
1091            "  int total = va_arg(ap, int) + va_arg(copy, int);\n",
1092            "  va_end(ap);\n",
1093            "  va_end(copy);\n",
1094            "  return total;\n",
1095            "}\n",
1096        ));
1097        assert!(text.contains("va-start"), "{text}");
1098        assert!(text.contains("va-copy"), "{text}");
1099        assert!(text.contains("va-arg"), "{text}");
1100        assert!(text.contains("va-end"), "{text}");
1101    }
1102
1103    /// glibc includes `<stdarg.h>` this way from every header that declares a `vprintf`, and
1104    /// what it wants is the type without the four macro names. Answering the whole header
1105    /// would put `va_start` in the way of a program that has its own.
1106    #[test]
1107    fn stdarg_hands_out_the_type_alone_when_that_is_all_that_was_asked_for() {
1108        let text = shipped(concat!(
1109            "#define __need___va_list\n",
1110            "#include <stdarg.h>\n",
1111            "int vprint(const char *f, __gnuc_va_list ap);\n",
1112            "#ifdef va_start\n",
1113            "#error va_start should not be defined\n",
1114            "#endif\n",
1115            "#ifdef _VA_LIST_DEFINED\n",
1116            "#error va_list should not have been made\n",
1117            "#endif\n",
1118        ));
1119        assert!(text.contains("vprint"), "{text}");
1120    }
1121
1122    /// The same protocol on `<stddef.h>`, which glibc uses far more heavily: `<stdio.h>` asks
1123    /// for `size_t` and `NULL` and would be wrong to receive `offsetof` as well.
1124    #[test]
1125    fn stddef_answers_one_piece_at_a_time_and_the_next_request_still_gets_through() {
1126        let text = shipped(concat!(
1127            "#define __need_size_t\n",
1128            "#include <stddef.h>\n",
1129            "#ifdef offsetof\n",
1130            "#error offsetof should not be defined yet\n",
1131            "#endif\n",
1132            "#define __need_ptrdiff_t\n",
1133            "#include <stddef.h>\n",
1134            "#include <stddef.h>\n",
1135            "size_t a;\n",
1136            "ptrdiff_t b;\n",
1137            "wchar_t c;\n",
1138            "max_align_t d;\n",
1139            "void *e = NULL;\n",
1140            "struct P { int x; long y; };\n",
1141            "size_t f = offsetof(struct P, y);\n",
1142        ));
1143        assert!(text.contains("decl #0 a : unsigned long"), "{text}");
1144        assert!(text.contains("decl #1 b : long"), "{text}");
1145    }
1146
1147    #[test]
1148    fn the_shipped_limits_and_float_are_the_targets_own_answers() {
1149        let text = shipped(concat!(
1150            "#include <limits.h>\n",
1151            "#include <float.h>\n",
1152            "int bits = CHAR_BIT;\n",
1153            "long big = LONG_MAX;\n",
1154            "int low = INT_MIN;\n",
1155            "int radix = FLT_RADIX;\n",
1156            "int digits = DBL_MANT_DIG;\n",
1157        ));
1158        assert!(text.contains("const 8 : int"), "{text}");
1159        assert!(text.contains("const 9223372036854775807 : long"), "{text}");
1160        assert!(text.contains("const 2 : int"), "{text}");
1161        assert!(text.contains("const 53 : int"), "{text}");
1162    }
1163
1164    /// Freestanding, so there is no library header to chain to and `<stdint.h>` writes the
1165    /// whole set out itself. The widths are the ones the target picked, which is the only
1166    /// reason this header is the compiler's.
1167    #[test]
1168    fn the_shipped_stdint_writes_the_whole_set_when_there_is_no_library_to_defer_to() {
1169        let text = shipped(concat!(
1170            "#include <stdint.h>\n",
1171            "int64_t a = INT64_C(1);\n",
1172            "uint_least16_t b;\n",
1173            "intptr_t c;\n",
1174            "uintmax_t d = UINTMAX_MAX;\n",
1175            "int wide = sizeof(int_fast64_t);\n",
1176        ));
1177        assert!(text.contains("decl #0 a : long"), "{text}");
1178        assert!(text.contains("decl #1 b : unsigned short"), "{text}");
1179        assert!(text.contains("decl #2 c : long"), "{text}");
1180    }
1181
1182    /// `<mmintrin.h>` is the base of the vector header chain and the first one whose contents
1183    /// are C rather than declarations, so what this checks is that the C in it compiles: a
1184    /// header that is nothing but definitions fails as a whole or not at all.
1185    ///
1186    /// What the intrinsics answer is not checked here and cannot be, because the answer is
1187    /// only interesting next to another compiler's. Every intrinsic in the header was built
1188    /// and run against GCC 16.2.0 on the same inputs, at `-O0`, `-O1`, `-O2` and `-Os`, and
1189    /// gave the same bytes in all four. Carrying that comparison rather than repeating it by
1190    /// hand needs a facet in `tamnd/rucc-corpus` that works out the expected bytes itself,
1191    /// which is a second implementation of MMX and is `tamnd/rucc#1150`.
1192    #[test]
1193    fn the_shipped_mmintrin_defines_the_mmx_type_and_the_operations_over_it() {
1194        let text = shipped(concat!(
1195            "#include <mmintrin.h>\n",
1196            "__m64 add(__m64 a, __m64 b) { return _mm_add_pi16(a, b); }\n",
1197            "__m64 pack(__m64 a, __m64 b) { return _m_packsswb(a, b); }\n",
1198            "__m64 shift(__m64 a) { return _mm_srai_pi32(a, 3); }\n",
1199            "int low(__m64 a) { return _mm_cvtsi64_si32(a); }\n",
1200            "void done(void) { _mm_empty(); }\n",
1201        ));
1202        assert!(text.contains("add"), "{text}");
1203        assert!(text.contains("pack"), "{text}");
1204        assert!(text.contains("shift"), "{text}");
1205    }
1206
1207    /// The allocator beside the vector headers, which is the one piece of the family that is
1208    /// not a vector operation. It reaches for `<stddef.h>` and for three names out of the
1209    /// library, and the point of the test is that the reach resolves with nothing on the
1210    /// search path but the compiler's own directory.
1211    #[test]
1212    fn the_shipped_mm_malloc_asks_for_aligned_memory_and_gives_it_back() {
1213        let text = shipped(concat!(
1214            "#include <mm_malloc.h>\n",
1215            "void *get(void) { return _mm_malloc(64, 16); }\n",
1216            "void put(void *p) { _mm_free(p); }\n",
1217        ));
1218        assert!(text.contains("get"), "{text}");
1219        assert!(text.contains("put"), "{text}");
1220    }
1221
1222    /// `<xmmintrin.h>` is the next rung of the chain and pulls the other two in behind it, so a
1223    /// program that includes this one alone has to get all three. What the intrinsics answer is
1224    /// checked the same way `<mmintrin.h>` next door is checked and for the same reason: a
1225    /// hundred and forty eight lines of answers over nans, infinities, both zeros and values
1226    /// that do not fit in the integer they convert to, identical to GCC 16.2.0 at `-O0`, `-O1`,
1227    /// `-O2` and `-Os`.
1228    ///
1229    /// `_mm_rcp_ps` is the one answer in that run that is not identical, and is not meant to be.
1230    /// The instruction approximates a reciprocal and this computes one exactly, so the bits
1231    /// differ while both sit inside the relative error Intel documents, which the same program
1232    /// checks directly rather than by comparing bits.
1233    #[test]
1234    fn the_shipped_xmmintrin_defines_the_sse_type_and_the_operations_over_it() {
1235        let text = shipped(concat!(
1236            "#include <xmmintrin.h>\n",
1237            "__m128 add(__m128 a, __m128 b) { return _mm_add_ps(a, b); }\n",
1238            "__m128 one(__m128 a, __m128 b) { return _mm_max_ss(a, b); }\n",
1239            "__m128 mask(__m128 a, __m128 b) { return _mm_cmpnle_ps(a, b); }\n",
1240            "__m128 pick(__m128 a, __m128 b) { return _mm_shuffle_ps(a, b, _MM_SHUFFLE(0,1,2,3)); }\n",
1241            "int bits(__m128 a) { return _mm_movemask_ps(a); }\n",
1242            "int near(__m128 a) { return _mm_cvtss_si32(a); }\n",
1243            "__m128 wide(__m64 a) { return _mm_cvtpi16_ps(a); }\n",
1244            "void *room(void) { return _mm_malloc(64, 16); }\n",
1245            "void hint(const float *p) { _mm_prefetch(p, _MM_HINT_T0); _mm_sfence(); }\n",
1246        ));
1247        assert!(text.contains("add"), "{text}");
1248        assert!(text.contains("mask"), "{text}");
1249        assert!(text.contains("pick"), "{text}");
1250        assert!(text.contains("wide"), "{text}");
1251    }
1252
1253    /// The six names of gcc's header this one leaves out, each of which is an instruction whose
1254    /// answer no plain C reproduces exactly. Leaving them out is what turns a program that wants
1255    /// one into a diagnostic naming the function it called, rather than into a wrong answer, and
1256    /// this is what notices if one is ever quietly defined to something close.
1257    ///
1258    /// `tamnd/rucc#1157` is the square root, which brings the first four back.
1259    #[test]
1260    fn the_shipped_xmmintrin_leaves_out_the_names_that_need_an_instruction() {
1261        let text = rucc_session::runtime::header("xmmintrin.h").expect("xmmintrin.h is shipped");
1262        for absent in [
1263            "_mm_sqrt_ps",
1264            "_mm_sqrt_ss",
1265            "_mm_rsqrt_ps",
1266            "_mm_rsqrt_ss",
1267            "_mm_getcsr",
1268            "_mm_setcsr",
1269        ] {
1270            let defined = text.contains(&format!("{absent}("));
1271            assert!(!defined, "{absent} is defined and the header says it is not");
1272            assert!(text.contains(absent), "{absent} is absent and unexplained");
1273        }
1274    }
1275
1276    #[test]
1277    fn the_shipped_emmintrin_defines_both_sse2_types_and_the_operations_over_them() {
1278        let text = shipped(concat!(
1279            "#include <emmintrin.h>\n",
1280            "__m128i add(__m128i a, __m128i b) { return _mm_add_epi64(a, b); }\n",
1281            "__m128i wide(__m128i a, __m128i b) { return _mm_mul_epu32(a, b); }\n",
1282            "__m128i pick(__m128i a) { return _mm_shuffle_epi32(a, _MM_SHUFFLE(0,1,2,3)); }\n",
1283            "__m128i up(__m128i a) { return _mm_slli_epi64(a, 13); }\n",
1284            "__m128i down(__m128i a) { return _mm_srli_si128(a, 3); }\n",
1285            "__m128i pack(__m128i a, __m128i b) { return _mm_packus_epi16(a, b); }\n",
1286            "int bits(__m128i a) { return _mm_movemask_epi8(a); }\n",
1287            "__m128d sum(__m128d a, __m128d b) { return _mm_add_sd(a, b); }\n",
1288            "__m128d mask(__m128d a, __m128d b) { return _mm_cmpunord_pd(a, b); }\n",
1289            "__m128i near(__m128d a) { return _mm_cvtpd_epi32(a); }\n",
1290            "__m128d over(__m128 a) { return _mm_cvtps_pd(a); }\n",
1291            "__m128i half(__m64 a) { return _mm_movpi64_epi64(a); }\n",
1292            "__m128i grab(void const *p) { return _mm_loadu_si128(p); }\n",
1293            "void wall(void) { _mm_lfence(); _mm_mfence(); }\n",
1294        ));
1295        assert!(text.contains("wide"), "{text}");
1296        assert!(text.contains("pack"), "{text}");
1297        assert!(text.contains("near"), "{text}");
1298        assert!(text.contains("half"), "{text}");
1299    }
1300
1301    /// The umbrella header reaches the three underneath it. This is brotli's use of it, from
1302    /// `c/enc/matching_tag_mask.h`, which is the whole of what `tamnd/rucc#1236` was about: four
1303    /// SSE2 names that were already shipped and no way to get at them by the name gcc uses.
1304    #[test]
1305    fn the_shipped_immintrin_reaches_the_names_the_headers_under_it_define() {
1306        let text = shipped(concat!(
1307            "#include <immintrin.h>\n",
1308            "unsigned long long matching(unsigned char tag, unsigned char const *bucket) {\n",
1309            "  __m128i const want = _mm_set1_epi8((char)tag);\n",
1310            "  __m128i const chunk = _mm_loadu_si128((__m128i const *)(void const *)bucket);\n",
1311            "  __m128i const same = _mm_cmpeq_epi8(chunk, want);\n",
1312            "  return (unsigned long long)_mm_movemask_epi8(same);\n",
1313            "}\n",
1314            "__m64 narrow(__m64 a, __m64 b) { return _mm_add_pi32(a, b); }\n",
1315            "__m128 single(__m128 a, __m128 b) { return _mm_add_ps(a, b); }\n",
1316        ));
1317        assert!(text.contains("matching"), "{text}");
1318        assert!(text.contains("narrow"), "the MMX header is not reached: {text}");
1319        assert!(text.contains("single"), "the SSE header is not reached: {text}");
1320    }
1321
1322    /// The wider umbrella reaches everything the narrower one does, and the fence family with it.
1323    /// This is what mingw-w64's `<winnt.h>` includes and what it then uses, so a Windows program
1324    /// that has never heard of an intrinsic gets here through `<windows.h>`.
1325    #[test]
1326    fn the_shipped_x86intrin_reaches_the_fences_windows_headers_ask_it_for() {
1327        let text = shipped(concat!(
1328            "#include <x86intrin.h>\n",
1329            "void barriers(void *p) {\n",
1330            "  _mm_lfence();\n",
1331            "  _mm_sfence();\n",
1332            "  _mm_mfence();\n",
1333            "  _mm_pause();\n",
1334            "  _mm_clflush(p);\n",
1335            "}\n",
1336            "__m128i wide(__m128i a, __m128i b) { return _mm_add_epi32(a, b); }\n",
1337        ));
1338        assert!(text.contains("barriers"), "{text}");
1339        assert!(text.contains("wide"), "the SSE2 header is not reached: {text}");
1340    }
1341
1342    /// Including it twice is the same as including it once, and so is including it beside the
1343    /// header it reaches. A program that includes both spellings is the usual case rather than an
1344    /// odd one, because one of its own headers includes the umbrella and another includes SSE2.
1345    #[test]
1346    fn the_umbrella_and_the_header_under_it_can_both_be_included() {
1347        let text = shipped(concat!(
1348            "#include <immintrin.h>\n",
1349            "#include <emmintrin.h>\n",
1350            "#include <immintrin.h>\n",
1351            "#include <x86intrin.h>\n",
1352            "__m128i twice(__m128i a, __m128i b) { return _mm_add_epi32(a, b); }\n",
1353        ));
1354        assert!(text.contains("twice"), "{text}");
1355    }
1356
1357    /// The float header omits four square roots and SSE2 omits the matching two, for the reason
1358    /// both headers write down. A later change that quietly defines one as an approximation
1359    /// would be a wrong answer nobody sees, so the absence is held in place here.
1360    #[test]
1361    fn the_shipped_emmintrin_leaves_out_the_two_square_roots() {
1362        let text = rucc_session::runtime::header("emmintrin.h").expect("emmintrin.h is shipped");
1363        for absent in ["_mm_sqrt_pd", "_mm_sqrt_sd"] {
1364            let defined = text.contains(&format!("{absent}("));
1365            assert!(!defined, "{absent} is defined and the header says it is not");
1366            assert!(text.contains(absent), "{absent} is absent and unexplained");
1367        }
1368    }
1369
1370    #[test]
1371    fn the_three_formality_headers_still_have_to_work() {
1372        let text = shipped(concat!(
1373            "#include <stdbool.h>\n",
1374            "#include <stdalign.h>\n",
1375            "#include <iso646.h>\n",
1376            "#include <stdnoreturn.h>\n",
1377            "int t = true and not false;\n",
1378            "_Alignas(16) char buf[16];\n",
1379            "int a = alignof(long);\n",
1380        ));
1381        assert!(text.contains("decl #0 t : int"), "{text}");
1382        assert!(text.contains("const 8 : unsigned long"), "{text}");
1383    }
1384
1385    /// Including everything twice has to change nothing, because that is what happens in any
1386    /// program large enough to matter and a guard that is wrong shows up nowhere else.
1387    ///
1388    /// Stated as the two trees being the same rather than as a fact about what is in either
1389    /// one. A header that carries definitions puts them in the tree and moves everything
1390    /// after them along, so an assertion about where the program's own declaration landed is
1391    /// an assertion about how much `<mmintrin.h>` defines, which is not what is being asked.
1392    #[test]
1393    fn every_shipped_header_can_be_included_twice() {
1394        let once: String = rucc_session::runtime::names()
1395            .iter()
1396            .map(|name| format!("#include <{name}>\n"))
1397            .collect();
1398        let twice = once.repeat(2);
1399        assert_eq!(shipped(&format!("{once}int x;\n")), shipped(&format!("{twice}int x;\n")));
1400    }
1401
1402    #[test]
1403    fn a_file_that_is_not_there_says_so_and_produces_nothing() {
1404        let fs = MemoryFileSystem::new();
1405        let result = compile(&options(), "/nope.c", &fs);
1406        assert!(result.failed());
1407        assert!(result.messages[0].contains("/nope.c"), "{:?}", result.messages);
1408        assert!(result.text().is_empty());
1409    }
1410
1411    #[test]
1412    fn an_object_comes_out_with_its_type_its_linkage_and_how_much_of_a_definition_it_is() {
1413        let text = tast("int x = 1;\n");
1414        let expected = "\
1415decl #0 x : int object external static defined
1416  init
1417    +0
1418      const 1 : int
1419";
1420        assert_eq!(text, expected);
1421    }
1422
1423    #[test]
1424    fn the_macros_are_expanded_before_anything_is_parsed() {
1425        // The whole pipeline in one line. The bound came out of a macro, so it was expanded,
1426        // converted from a preprocessing number to a constant of a type, parsed as an
1427        // expression, and folded to the number the array type carries.
1428        let text = tast("#define N 2\nint a[N];\n");
1429        assert!(text.starts_with("decl #0 a : int[2] object external static tentative"), "{text}");
1430    }
1431
1432    /// A pragma survives the preprocessor on purpose, since what one means is not its
1433    /// business, and nothing after it has a place for a `#` in the grammar. `pack` is the one
1434    /// the parser reads and every other line is walked past. Both spellings are here because
1435    /// they arrive by different routes and only one of them was ever on a line of its own in
1436    /// the source.
1437    #[test]
1438    fn a_pragma_is_not_a_declaration_and_the_parse_walks_past_the_ones_it_does_not_read() {
1439        let text = tast(concat!(
1440            "#pragma pack(4)\n",
1441            "struct s { int a; };\n",
1442            "#pragma pack()\n",
1443            "int b;\n",
1444            "_Pragma(\"GCC visibility push(default)\") int c;\n",
1445        ));
1446        assert!(text.contains("decl #0 b : int"), "{text}");
1447        assert!(text.contains("decl #1 c : int"), "{text}");
1448    }
1449
1450    /// Every number in these two tests was read off gcc 16 on x86-64 under `-std=gnu23`
1451    /// rather than reasoned about, which is why they are written as assertions the program
1452    /// makes about itself: a compilation with no messages is every one of them holding.
1453    ///
1454    /// This half is the attributes. `packed` takes the padding out, on the record or on one
1455    /// member, `aligned` raises and never lowers, and the two written together are the
1456    /// combination that packs and then aligns the whole thing.
1457    #[test]
1458    fn the_layout_attributes_move_the_members_and_the_record_the_way_gcc_lays_them_out() {
1459        tast(concat!(
1460            "struct A { char c; int i; } __attribute__((packed));\n",
1461            "_Static_assert(sizeof(struct A) == 5 && _Alignof(struct A) == 1, \"A\");\n",
1462            "_Static_assert(__builtin_offsetof(struct A, i) == 1, \"A.i\");\n",
1463            // `aligned` with nothing in the parentheses is the largest alignment the target
1464            // has, which gcc calls BIGGEST_ALIGNMENT and which is sixteen everywhere here.
1465            "struct B { char c; int i; } __attribute__((aligned));\n",
1466            "_Static_assert(sizeof(struct B) == 16 && _Alignof(struct B) == 16, \"B\");\n",
1467            "struct C { char c; int i __attribute__((packed)); };\n",
1468            "_Static_assert(sizeof(struct C) == 5 && _Alignof(struct C) == 1, \"C\");\n",
1469            "_Static_assert(__builtin_offsetof(struct C, i) == 1, \"C.i\");\n",
1470            "struct D { char c; int i; } __attribute__((packed, aligned(4)));\n",
1471            "_Static_assert(sizeof(struct D) == 8 && _Alignof(struct D) == 4, \"D\");\n",
1472            "_Static_assert(__builtin_offsetof(struct D, i) == 1, \"D.i\");\n",
1473            "struct E { char c; _Alignas(8) int i; };\n",
1474            "_Static_assert(sizeof(struct E) == 16 && _Alignof(struct E) == 8, \"E\");\n",
1475            "_Static_assert(__builtin_offsetof(struct E, i) == 8, \"E.i\");\n",
1476            "struct F { char c; int i __attribute__((aligned(8))); };\n",
1477            "_Static_assert(sizeof(struct F) == 16 && _Alignof(struct F) == 8, \"F\");\n",
1478            // Two the record already had, so the attribute asks for nothing new, and two
1479            // where four was already there, so the attribute is ignored rather than obeyed.
1480            "struct G { char c; short s; } __attribute__((aligned(2)));\n",
1481            "_Static_assert(sizeof(struct G) == 4 && _Alignof(struct G) == 2, \"G\");\n",
1482            "struct H { char c; int i; } __attribute__((aligned(2)));\n",
1483            "_Static_assert(sizeof(struct H) == 8 && _Alignof(struct H) == 4, \"H\");\n",
1484            // `packed` on a member takes the padding out in front of that member alone, so on
1485            // the first one it does nothing and on the second one it does all of it.
1486            "struct I { [[gnu::packed]] char c; int i; };\n",
1487            "_Static_assert(sizeof(struct I) == 8 && _Alignof(struct I) == 4, \"I\");\n",
1488            "struct J { char c; [[gnu::packed]] int i; };\n",
1489            "_Static_assert(sizeof(struct J) == 5 && _Alignof(struct J) == 1, \"J\");\n",
1490            "struct M { char c; int i : 5; int j : 20; } __attribute__((packed));\n",
1491            "_Static_assert(sizeof(struct M) == 5 && _Alignof(struct M) == 1, \"M\");\n",
1492            "struct N { char c; long long l; } __attribute__((aligned(32)));\n",
1493            "_Static_assert(sizeof(struct N) == 32 && _Alignof(struct N) == 32, \"N\");\n",
1494            "union L { char c; int i; } __attribute__((packed));\n",
1495            "_Static_assert(sizeof(union L) == 4 && _Alignof(union L) == 1, \"L\");\n",
1496            // The armoured spellings, which are the ones a system header writes, since a
1497            // program is entitled to a macro called `packed` and is not entitled to one called
1498            // `__packed__`. The two names are one attribute and the layout is the same one.
1499            "struct O { char c; int i; } __attribute__((__packed__));\n",
1500            "_Static_assert(sizeof(struct O) == 5 && _Alignof(struct O) == 1, \"O\");\n",
1501            "struct P { char c; int i; } __attribute__((__aligned__(8)));\n",
1502            "_Static_assert(sizeof(struct P) == 8 && _Alignof(struct P) == 8, \"P\");\n",
1503        ));
1504    }
1505
1506    /// The attribute that changes what a call means rather than what a record lays out.
1507    ///
1508    /// Both halves are here. A call hands a value to a parameter of the union type and the value
1509    /// goes into the member that takes it, which is a compound literal of the union and is the
1510    /// same object the GNU cast to a union builds. And a declaration written with a member's type
1511    /// declares the same function as one written with the union, which is what lets a pointer to
1512    /// either be assigned from the other, and is what gnulib's signature checks do.
1513    ///
1514    /// The `void *` member is last on purpose: the search takes a member whose type the value
1515    /// already has wherever it sits, and falls back to a pointer member that would take the value
1516    /// silently only when there is no such member, so `char *` reaches the catch-all past two
1517    /// members that are not it.
1518    #[test]
1519    fn a_transparent_union_takes_the_member_a_value_fits_and_is_declared_either_way() {
1520        let text = tast(concat!(
1521            "struct one { int x; };\n",
1522            "struct two { long y; };\n",
1523            "typedef union { struct one *a; struct two *b; void *any; }\n",
1524            "  __attribute__((__transparent_union__)) arg;\n",
1525            "int takes(arg v);\n",
1526            "int f(struct one *p, struct two *q, char *c) {\n",
1527            "  return takes(p) + takes(q) + takes(c) + takes(0);\n",
1528            "}\n",
1529            // The other half, which is about declarations and not about values.
1530            "int takes(struct one *p);\n",
1531            "int (*as_a_member)(struct one *) = takes;\n",
1532            "int (*as_the_union)(arg) = takes;\n",
1533        ));
1534        assert!(text.contains("compound-literal"), "{text}");
1535    }
1536
1537    /// The other place glibc writes it, which is the one that matters.
1538    ///
1539    /// `sys/socket.h` puts the attribute on the declarator of the typedef rather than after the
1540    /// closing brace, so a compiler that reads only the second position reads nothing at all of
1541    /// the eleven pointer union that `bind` and `connect` and five others take.
1542    #[test]
1543    fn the_attribute_on_the_declarator_of_a_typedef_is_the_one_glibc_writes() {
1544        let text = tast(concat!(
1545            "struct sockaddr { int family; };\n",
1546            "struct sockaddr_in { int family; int addr; };\n",
1547            "typedef union { struct sockaddr *plain; struct sockaddr_in *inet; }\n",
1548            "  addr_arg __attribute__((__transparent_union__));\n",
1549            "int bind_to(int fd, addr_arg where);\n",
1550            "int f(struct sockaddr_in *where) { return bind_to(0, where); }\n",
1551        ));
1552        assert!(text.contains("compound-literal"), "{text}");
1553    }
1554
1555    /// What the attribute promises has to be a promise this can keep, and is checked rather than
1556    /// believed.
1557    ///
1558    /// A union wider than its first member is not passed the way that member is, and a structure
1559    /// has no members that are alternatives to each other at all. gcc drops the attribute in both
1560    /// cases with a warning and compiles the program, because the type is still a perfectly good
1561    /// type and only the extra rule is gone.
1562    #[test]
1563    fn a_transparent_union_that_cannot_keep_the_promise_is_dropped_with_a_word_about_it() {
1564        let result = run(
1565            &options(),
1566            concat!(
1567                "union wider { int small; double large; } __attribute__((transparent_union));\n",
1568                "struct plain { int x; } __attribute__((transparent_union));\n",
1569            ),
1570        );
1571        assert_eq!(result.messages.len(), 2, "{:?}", result.messages);
1572        assert!(!result.failed(), "{:?}", result.messages);
1573        for message in &result.messages {
1574            assert!(message.contains("'transparent_union' attribute ignored"), "{message}");
1575        }
1576        assert!(result.messages[0].contains("first member"), "{:?}", result.messages);
1577        assert!(result.messages[1].contains("only a union"), "{:?}", result.messages);
1578    }
1579
1580    /// What an access to a packed member is allowed to assume about where it starts.
1581    ///
1582    /// C 6.2.8 gives an object of type `int` four byte alignment and `packed` takes it away: the
1583    /// member goes wherever the members in front of it ended, and an `int` one byte into a record
1584    /// is aligned to one. The number on the access has to say so, because it is what the back end
1585    /// picks instructions from and what judgement J1 of `spec/safe-memory/04-safety-model.md`
1586    /// tests at run time. Four on an address that is a multiple of one is the compiler refusing a
1587    /// program that is doing nothing wrong.
1588    #[test]
1589    fn an_access_to_a_packed_member_says_the_alignment_the_layout_left_it() {
1590        let packed = body(concat!(
1591            "struct P { char c; int v; } __attribute__((packed));\n",
1592            "int f(struct P *p) { return p->v; }\n",
1593        ));
1594        assert!(packed.contains("load.i32 %2, align 1,"), "{packed}");
1595        // The same record without the attribute, which is where the type's own answer is right.
1596        let plain = body(concat!(
1597            "struct P { char c; int v; };\n",
1598            "int f(struct P *p) { return p->v; }\n",
1599        ));
1600        assert!(plain.contains("load.i32 %2, align 4,"), "{plain}");
1601    }
1602
1603    /// The same, for the two ways of being further in than the member itself.
1604    ///
1605    /// An array member is stepped through rather than offset to, and a record member is offset to
1606    /// twice, and both have to carry the outer record's alignment with them. A step of a whole
1607    /// number of elements leaves what the element width and the address had in common, which for
1608    /// a one byte aligned base is one byte however wide the elements are.
1609    #[test]
1610    fn what_is_inside_a_packed_member_is_no_more_aligned_than_the_member_is() {
1611        let stepped = body(concat!(
1612            "struct P { char c; int v[4]; } __attribute__((packed));\n",
1613            "int f(struct P *p, int i) { return p->v[i]; }\n",
1614        ));
1615        assert!(stepped.contains(", align 1,"), "{stepped}");
1616        assert!(!stepped.contains(", align 4,"), "{stepped}");
1617        let nested = body(concat!(
1618            "struct Inner { int v; };\n",
1619            "struct P { char c; struct Inner in; } __attribute__((packed));\n",
1620            "int f(struct P *p) { return p->in.v; }\n",
1621        ));
1622        assert!(nested.contains(", align 1,"), "{nested}");
1623        assert!(!nested.contains(", align 4,"), "{nested}");
1624    }
1625
1626    /// The same attribute on a declaration rather than on a type, which asks that this object or
1627    /// this function be at a multiple of that, and which is where a program that has to hand a
1628    /// buffer to hardware or keep two counters off one cache line writes it.
1629    ///
1630    /// A raise and never a lower, which is the one place it does not agree with `_Alignas`: below
1631    /// what the type already has, `_Alignas` is a constraint violation and this is ignored without
1632    /// a word. `__alignof__` of the object answers what the object got and not what its type has,
1633    /// because that is the question a program asking it is asking.
1634    #[test]
1635    fn the_aligned_attribute_on_a_declaration_raises_what_that_one_object_is_aligned_to() {
1636        tast(concat!(
1637            "int v __attribute__((aligned(64)));\n",
1638            "_Static_assert(__alignof__(v) == 64, \"v\");\n",
1639            // Written on the specifiers rather than after the declarator, which asks the same
1640            // thing and is the spelling a header is more likely to use.
1641            "__attribute__((aligned(32))) int w;\n",
1642            "_Static_assert(__alignof__(w) == 32, \"w\");\n",
1643            "[[gnu::aligned(16)]] int x;\n",
1644            "_Static_assert(__alignof__(x) == 16, \"x\");\n",
1645            // Two below the four an `int` already has, so nothing is asked for and nothing is
1646            // said, and the type still answers for the object.
1647            "int y __attribute__((aligned(2)));\n",
1648            "_Static_assert(__alignof__(y) == 4, \"y\");\n",
1649            // A local, which is the same question one scope down.
1650            "void f(void) { int a __attribute__((aligned(128)));\n",
1651            "_Static_assert(__alignof__(a) == 128, \"a\"); (void)a; }\n",
1652            // The type is untouched by any of it: `aligned` on a declaration says where that
1653            // declaration goes and says nothing about every other `int` in the program.
1654            "_Static_assert(__alignof__(int) == 4, \"int\");\n",
1655            // A function, which has no alignment of its own for this to be measured against and
1656            // takes whatever was asked for.
1657            "void g(void) __attribute__((aligned(256)));\n",
1658            "void g(void) {}\n",
1659            "_Static_assert(__alignof__(g) == 256, \"g\");\n",
1660        ));
1661    }
1662
1663    /// And what the object file says, which is the half that makes the answer above true. A
1664    /// function is at a fixed offset inside the text section, so it is at a multiple of two
1665    /// hundred and fifty six only if the section is at one too.
1666    #[test]
1667    fn what_a_declaration_asked_to_be_aligned_to_is_what_the_assembler_is_told() {
1668        let text = asm(concat!(
1669            "int v __attribute__((aligned(64)));\n",
1670            "void g(void) __attribute__((aligned(256)));\n",
1671            "void g(void) {}\n",
1672            "void plain(void) {}\n",
1673        ));
1674        assert!(text.contains("\t.p2align\t6\n\t.type\tv, @object\n"), "{text}");
1675        assert!(text.contains("\t.p2align\t8, 0x90\n\t.globl\tg\n"), "{text}");
1676        assert!(text.contains("\t.p2align\t4, 0x90\n\t.globl\tplain\n"), "{text}");
1677    }
1678
1679    /// And the one position where the attribute means something else. On a declaration it raises
1680    /// what that one object is aligned to, and on a typedef it says what the type is aligned to,
1681    /// which gcc lets it lower as well: `typedef int L __attribute__((aligned(2)))` really is an
1682    /// `int` at a multiple of two and a record with one in it really is smaller for it.
1683    ///
1684    /// The size is left alone, which is gcc's answer rather than an omission here. An aligned
1685    /// typedef whose alignment is larger than what it stands for keeps the size it stands for,
1686    /// and gcc refuses an array of one rather than padding the elements out to fit.
1687    #[test]
1688    fn an_aligned_typedef_says_what_an_object_of_it_is_aligned_to_and_may_lower_it() {
1689        tast(concat!(
1690            "typedef int L __attribute__((aligned(2)));\n",
1691            "_Static_assert(__alignof__(L) == 2, \"L\");\n",
1692            "_Static_assert(_Alignof(L) == 2, \"L alignof\");\n",
1693            // Below what an `int` has, which is the half a declaration cannot ask for.
1694            "_Static_assert(sizeof(L) == 4, \"L size\");\n",
1695            "struct T { char c; L x; };\n",
1696            "_Static_assert(sizeof(struct T) == 6, \"T\");\n",
1697            "_Static_assert(__builtin_offsetof(struct T, x) == 2, \"T.x\");\n",
1698            // And upwards, which is the ordinary direction and the one a header writes.
1699            "typedef int H __attribute__((aligned(16)));\n",
1700            "_Static_assert(__alignof__(H) == 16, \"H\");\n",
1701            "_Static_assert(sizeof(H) == 4, \"H size\");\n",
1702            "struct U { char c; H x; };\n",
1703            "_Static_assert(sizeof(struct U) == 32, \"U\");\n",
1704            "_Static_assert(__builtin_offsetof(struct U, x) == 16, \"U.x\");\n",
1705            // A typedef of a typedef, where the nearer one is the one the declaration was
1706            // written with and is the one that answers.
1707            "typedef L M __attribute__((aligned(8)));\n",
1708            "_Static_assert(__alignof__(M) == 8, \"M\");\n",
1709            // And one that asked for nothing, which still has whatever the one behind it asked
1710            // for because it is the same type spelled again.
1711            "typedef L N;\n",
1712            "_Static_assert(__alignof__(N) == 2, \"N\");\n",
1713            // The type it stands for is untouched by any of it.
1714            "_Static_assert(__alignof__(int) == 4, \"int\");\n",
1715        ));
1716        let text = asm(concat!(
1717            "typedef int L __attribute__((aligned(2)));\n",
1718            "typedef int H __attribute__((aligned(16)));\n",
1719            "L low;\n",
1720            "H high;\n",
1721        ));
1722        assert!(text.contains("\t.p2align\t1\n\t.type\tlow, @object\n"), "{text}");
1723        assert!(text.contains("\t.p2align\t4\n\t.type\thigh, @object\n"), "{text}");
1724    }
1725
1726    /// The attribute that builds a type rather than changing a layout. `vector_size(n)` says the
1727    /// declared type is `n` bytes of what was written, taken as lanes, and every operator over
1728    /// one is that operator over each lane.
1729    ///
1730    /// The size is in bytes and not in lanes, which is the part a reader gets backwards: sixteen
1731    /// of `int` is four lanes and sixteen of `char` is sixteen. A vector is aligned to its own
1732    /// size, which is what a machine that has the registers wants and what gcc gives one here.
1733    #[test]
1734    fn the_vector_size_attribute_builds_a_type_of_lanes_and_measures_it_in_bytes() {
1735        tast(concat!(
1736            "typedef int __attribute__((vector_size(16))) v4si;\n",
1737            "_Static_assert(sizeof(v4si) == 16 && _Alignof(v4si) == 16, \"v4si\");\n",
1738            "typedef char __attribute__((vector_size(16))) v16qi;\n",
1739            "_Static_assert(sizeof(v16qi) == 16, \"v16qi\");\n",
1740            // One lane, which is a power of two and is a vector rather than the type it was
1741            // written on: the operators it takes are the vector's and not the scalar's.
1742            "typedef int __attribute__((vector_size(4))) v1si;\n",
1743            "_Static_assert(sizeof(v1si) == 4, \"v1si\");\n",
1744            // The armoured spelling and the bracket one, which are the same attribute.
1745            "typedef float __attribute__((__vector_size__(8))) v2sf;\n",
1746            "_Static_assert(sizeof(v2sf) == 8, \"v2sf\");\n",
1747            "typedef short [[gnu::vector_size(8)]] v4hi;\n",
1748            "_Static_assert(sizeof(v4hi) == 8, \"v4hi\");\n",
1749            // A lane is what a subscript answers with, and a vector is not a pointer: there is
1750            // nothing to decay and the lane type is the one the arithmetic happens in.
1751            "v4si g;\n",
1752            "_Static_assert(sizeof(g[0]) == 4, \"lane\");\n",
1753            "_Static_assert(sizeof(g + g) == 16, \"whole\");\n",
1754            // A scalar beside a vector stands for itself in every lane, so the answer is still
1755            // the vector and not the wider of the two types.
1756            "_Static_assert(sizeof(g + 1) == 16, \"broadcast\");\n",
1757            // An array of them, which is the ordinary way a program holds several.
1758            "_Static_assert(sizeof(v4si[3]) == 48, \"array\");\n",
1759        ));
1760    }
1761
1762    /// A whole vector written into an array of them, and a vector named by a type name rather
1763    /// than by a typedef.
1764    ///
1765    /// Both are the same question asked twice. A vector is filled like an array of its lanes when
1766    /// a list is written into it, so a braced element that is itself a vector has to be taken
1767    /// whole rather than started as the first lane, and the type of what was written is the only
1768    /// thing that says which was meant. And a type name is where a compound literal and a cast
1769    /// spell the type out, which a macro taking a lane type and a lane count does, so the
1770    /// attribute has to be read there and not only on a declaration.
1771    #[test]
1772    fn a_vector_is_written_whole_into_an_array_of_them_and_named_by_a_type_name() {
1773        tast(concat!(
1774            "typedef int __attribute__((vector_size(8))) v2si;\n",
1775            "v2si table[] = { (v2si){ 1, 2 }, (v2si){ 3, 4 } };\n",
1776            "_Static_assert(sizeof(table) == 16, \"two of them and not eight lanes\");\n",
1777            // The size written out rather than named, which is the spelling a macro expands to.
1778            "v2si written = (int __attribute__((vector_size(8)))){ 5, 6 };\n",
1779            "_Static_assert(sizeof((int __attribute__((vector_size(16)))){ 0 }) == 16, \"named\");\n",
1780            // A lane is still a lane, so a list of them fills the vector the way it always did
1781            // and the rule above did not turn brace elision off.
1782            "v2si lanes[2] = { 1, 2, 3, 4 };\n",
1783            "_Static_assert(sizeof(lanes) == 16, \"still elided\");\n",
1784        ));
1785    }
1786
1787    /// A lane written rather than read, and a shift whose two vectors are not the same type.
1788    ///
1789    /// Both are places where a vector is not the aggregate it looks like. A subscript of one is
1790    /// an lvalue because the vector it came from is an object, so a lane can be assigned to and
1791    /// has an address, and a qualifier written on the vector reaches every lane the way it does
1792    /// on an array. And a shift is the one lanewise operator whose sides are not brought to a
1793    /// single type, since the right side counts rather than computes.
1794    #[test]
1795    fn a_lane_is_assignable_and_a_shift_takes_a_count_of_its_own_lane() {
1796        let result = run(
1797            &options(),
1798            concat!(
1799                "typedef int __attribute__((vector_size(16))) v4si;\n",
1800                "typedef unsigned __attribute__((vector_size(16))) v4ui;\n",
1801                "void write(v4si *out, v4ui a, v4si b, int n) {\n",
1802                "  v4si v = { 1, 2, 3, 4 };\n",
1803                "  v[0] = n;\n",
1804                "  v[1] += n;\n",
1805                "  v[2]++;\n",
1806                "  *&v[3] = n;\n",
1807                // The count is signed and the value is not, which no other operator allows.
1808                "  v4ui shifted = a >> b;\n",
1809                "  shifted <<= b;\n",
1810                // A scalar stands in every lane on either side of a shift, which is the half
1811                // that looks wrong: the shape of the answer comes off the count here.
1812                "  *out = v + (v4si)shifted + (1 << b);\n",
1813                "}\n",
1814                // A qualifier on the vector is a qualifier on the lane, so there is nothing here
1815                // to write to.
1816                "void refused(const v4si c) {\n",
1817                "  c[0] = 1;\n",
1818                "}\n",
1819            ),
1820        );
1821        assert_eq!(result.messages.len(), 1, "{:?}", result.messages);
1822        assert!(result.messages[0].contains("assignment of read-only"), "{:?}", result.messages);
1823    }
1824
1825    /// The third layout attribute, and the one that is refused rather than read. Reversing the
1826    /// byte order of every scalar in a record is not something a compiler can do half of, and a
1827    /// compilation that ignored it would lay the record out in the host's order and hand back
1828    /// every field with its bytes the wrong way round. Both spellings are here because a header
1829    /// writes the armoured one, and the member is here because the refusal has to arrive before
1830    /// the layout is used rather than after.
1831    #[test]
1832    fn a_record_that_asks_for_the_other_byte_order_is_refused_rather_than_laid_out_in_this_one() {
1833        let opts = options();
1834        let big = "struct s { int i; } __attribute__((scalar_storage_order(\"big-endian\")));\n";
1835        assert_eq!(
1836            run(&opts, big).messages,
1837            ["/main.c:1:36: error: 'scalar_storage_order' is not implemented yet [E0688]\n\
1838              /main.c:1:36: note: every scalar in this record would be read in the wrong byte \
1839              order"]
1840        );
1841
1842        let armoured =
1843            "struct s { int i; } __attribute__((__scalar_storage_order__(\"little-endian\")));\n";
1844        let messages = run(&opts, armoured).messages;
1845        assert!(messages[0].contains("[E0688]"), "{messages:?}");
1846
1847        // The attribute in front of the body reaches the same list as the one behind it, and
1848        // the C23 spelling in gcc's namespace is the same attribute written a third way.
1849        let front = "struct __attribute__((scalar_storage_order(\"big-endian\"))) s { int i; };\n";
1850        assert!(run(&opts, front).messages[0].contains("[E0688]"), "{front}");
1851        let standard = "struct s { int i; } [[gnu::scalar_storage_order(\"big-endian\")]];\n";
1852        assert!(run(&opts, standard).messages[0].contains("[E0688]"), "{standard}");
1853    }
1854
1855    /// Where a bit-field goes, which packing decides and which is the part of all this that
1856    /// is not what the names suggest. A bit-field goes at the next free bit unless that would
1857    /// make it span more storage than its own type occupies, and then it moves to the next
1858    /// boundary of its alignment. Any packing at all takes that rule out, and `#pragma pack`
1859    /// counts even where it lowers nothing, which is the fourth and seventh cases here.
1860    ///
1861    /// Nothing in the language can be asked where a bit-field is, since `offsetof` refuses one
1862    /// and every size below comes out the same either way, so what is asked is the byte a read
1863    /// of the field loads from.
1864    #[test]
1865    fn packing_is_what_decides_whether_a_bit_field_may_straddle_its_own_storage() {
1866        // A `char` field after twelve bits, which will not straddle unpacked and does packed.
1867        assert_eq!(bit_field_byte("struct s { int x : 12; char y : 6; };"), 2);
1868        assert_eq!(
1869            bit_field_byte("struct s { int x : 12; char y : 6; } __attribute__((packed));"),
1870            1
1871        );
1872        assert_eq!(
1873            bit_field_byte("struct s { int x : 12; __attribute__((packed)) char y : 6; };"),
1874            1
1875        );
1876        assert_eq!(bit_field_byte("#pragma pack(4)\nstruct s { int x : 12; char y : 6; };"), 1);
1877        // A thirty bit field after a byte, which is the case the rule was written for.
1878        assert_eq!(bit_field_byte("struct s { char x; int y : 30; };"), 4);
1879        assert_eq!(bit_field_byte("struct s { char x; int y : 30; } __attribute__((packed));"), 1);
1880        // Four is what an `int` asked for anyway, so this caps nothing and still counts.
1881        assert_eq!(bit_field_byte("#pragma pack(4)\nstruct s { char x; int y : 30; };"), 1);
1882        assert_eq!(bit_field_byte("#pragma pack(2)\nstruct s { char x; int y : 30; };"), 1);
1883    }
1884
1885    /// The byte a read of `s.y` loads from, which is where the bit-field was placed.
1886    fn bit_field_byte(record: &str) -> u64 {
1887        let source = format!("{record}\nint f(struct s *p) {{ return p->y; }}\n");
1888        let body = body(&source);
1889        let Some((before, _)) = body.split_once("ptr_add") else { return 0 };
1890        let (_, constant) = before.rsplit_once("iconst.i64 ").expect("an offset constant");
1891        constant.lines().next().expect("a line").trim().parse().expect("a byte offset")
1892    }
1893
1894    /// An attribute in the middle of a specifier list, which is where a member usually carries
1895    /// one and which was read and then thrown away. The `[[...]]` spelling and whatever was
1896    /// written in front of the declaration are collected as the list is walked and the
1897    /// `__attribute__` spelling is put straight on the specifiers, and the two were assigned
1898    /// over each other rather than joined.
1899    #[test]
1900    fn an_attribute_among_the_specifiers_is_kept_beside_the_ones_written_in_front() {
1901        tast(concat!(
1902            "struct a { char c; __attribute__((aligned(8))) int i; };\n",
1903            "_Static_assert(sizeof(struct a) == 16 && _Alignof(struct a) == 8, \"a\");\n",
1904            "_Static_assert(__builtin_offsetof(struct a, i) == 8, \"a.i\");\n",
1905            "struct b { char c; __attribute__((packed)) int i; };\n",
1906            "_Static_assert(sizeof(struct b) == 5 && _Alignof(struct b) == 1, \"b\");\n",
1907            "_Static_assert(__builtin_offsetof(struct b, i) == 1, \"b.i\");\n",
1908            "typedef struct { char c; int i; } __attribute__((packed)) c;\n",
1909            "_Static_assert(sizeof(c) == 5 && _Alignof(c) == 1, \"c\");\n",
1910        ));
1911    }
1912
1913    /// The other half, which is `#pragma pack`. It caps a member's alignment where `packed`
1914    /// drops it, so `pack(2)` leaves a `short` where it was and moves an `int`, and it caps a
1915    /// member the program asked to align as well, which is where the two differ. It is read
1916    /// at the closing brace of the body, so a line written in the middle of one settles the
1917    /// whole record rather than the members after it, and `push` and `pop` nest.
1918    #[test]
1919    fn pragma_pack_caps_every_member_and_is_read_where_the_body_closes() {
1920        tast(concat!(
1921            "#pragma pack(1)\n",
1922            "struct A { char c; int i; };\n",
1923            "_Static_assert(sizeof(struct A) == 5 && _Alignof(struct A) == 1, \"A\");\n",
1924            "_Static_assert(__builtin_offsetof(struct A, i) == 1, \"A.i\");\n",
1925            "#pragma pack()\n",
1926            "struct B { char c; int i; };\n",
1927            "_Static_assert(sizeof(struct B) == 8 && _Alignof(struct B) == 4, \"B\");\n",
1928            "#pragma pack(2)\n",
1929            "struct C { char c; int i; double d; };\n",
1930            "_Static_assert(sizeof(struct C) == 14 && _Alignof(struct C) == 2, \"C\");\n",
1931            "_Static_assert(__builtin_offsetof(struct C, d) == 6, \"C.d\");\n",
1932            // A member the program aligned, which `pack` caps and `packed` would not.
1933            "struct K { char c; int i __attribute__((aligned(8))); };\n",
1934            "_Static_assert(sizeof(struct K) == 6 && _Alignof(struct K) == 2, \"K\");\n",
1935            "_Static_assert(__builtin_offsetof(struct K, i) == 2, \"K.i\");\n",
1936            // The record's own `aligned` is not a member's, so it is not capped.
1937            "struct J { char c; int i; } __attribute__((aligned(8)));\n",
1938            "_Static_assert(sizeof(struct J) == 8 && _Alignof(struct J) == 8, \"J\");\n",
1939            "#pragma pack()\n",
1940            "#pragma pack(push, 1)\n",
1941            "struct D { char c; short s; };\n",
1942            "_Static_assert(sizeof(struct D) == 3 && _Alignof(struct D) == 1, \"D\");\n",
1943            "#pragma pack(pop)\n",
1944            "struct E { char c; short s; };\n",
1945            "_Static_assert(sizeof(struct E) == 4 && _Alignof(struct E) == 2, \"E\");\n",
1946            // Written in the middle of a body, and it still settles the whole record.
1947            "struct H { char c;\n",
1948            "#pragma pack(1)\n",
1949            "  int i; };\n",
1950            "_Static_assert(sizeof(struct H) == 5 && _Alignof(struct H) == 1, \"H\");\n",
1951            "#pragma pack(1)\n",
1952            "struct I { char c;\n",
1953            "#pragma pack()\n",
1954            "  int i; };\n",
1955            "_Static_assert(sizeof(struct I) == 8 && _Alignof(struct I) == 4, \"I\");\n",
1956            "#pragma pack()\n",
1957            // Nested pushes, each one giving back what the one under it had.
1958            "#pragma pack(push, 8)\n",
1959            "#pragma pack(push, 1)\n",
1960            "struct P { char c; int i; };\n",
1961            "_Static_assert(sizeof(struct P) == 5 && _Alignof(struct P) == 1, \"P\");\n",
1962            "#pragma pack(pop)\n",
1963            "struct Q { char c; int i; };\n",
1964            "_Static_assert(sizeof(struct Q) == 8 && _Alignof(struct Q) == 4, \"Q\");\n",
1965            "#pragma pack(pop)\n",
1966            // A cap above what every member already asks for changes nothing at all.
1967            "#pragma pack(16)\n",
1968            "struct R { char c; int i; };\n",
1969            "_Static_assert(sizeof(struct R) == 8 && _Alignof(struct R) == 4, \"R\");\n",
1970            "#pragma pack()\n",
1971            "#pragma pack(1)\n",
1972            "struct S { char c; int i : 5; int j : 20; };\n",
1973            "_Static_assert(sizeof(struct S) == 5 && _Alignof(struct S) == 1, \"S\");\n",
1974            "union T { char c; int i; };\n",
1975            "_Static_assert(sizeof(union T) == 4 && _Alignof(union T) == 1, \"T\");\n",
1976            "#pragma pack()\n",
1977        ));
1978    }
1979
1980    /// A line the reader cannot make sense of is a warning and the line is dropped, which is
1981    /// what GCC does with one, and these are its words for each of them. The last line is the
1982    /// one nothing else would reach, since it stands after every record in the file.
1983    #[test]
1984    fn a_pack_line_that_is_not_one_is_reported_in_the_words_gcc_uses() {
1985        let result = run(
1986            &options(),
1987            concat!(
1988                "#pragma pack 4\n",
1989                "#pragma pack(pop)\n",
1990                "#pragma pack(3)\n",
1991                "#pragma pack(1) junk\n",
1992                "#pragma pack(push, 1\n",
1993                "#pragma pack(x)\n",
1994                // These two are well formed and say nothing. Zero is how a line asks for the
1995                // target's own alignments back without writing empty parentheses.
1996                "#pragma pack(0)\n",
1997                "#pragma pack(push)\n",
1998                "struct s { char c; int i; };\n",
1999                "#pragma pack(pop)\n",
2000                "#pragma pack(pop, foo)\n",
2001            ),
2002        );
2003        let expected = [
2004            "missing `(` after `#pragma pack` - ignored",
2005            "`#pragma pack (pop)` encountered without matching `#pragma pack (push)`",
2006            "alignment must be a small power of two, not 3",
2007            "junk at end of `#pragma pack`",
2008            "malformed `#pragma pack(push[, id][, <n>])` - ignored",
2009            "unknown action `x` for `#pragma pack` - ignored",
2010            "`#pragma pack(pop, foo)` encountered without matching `#pragma pack(push, foo)`",
2011        ];
2012        assert_eq!(result.messages.len(), expected.len(), "{:?}", result.messages);
2013        for (message, want) in result.messages.iter().zip(expected) {
2014            assert!(message.contains(want), "expected {want:?} in {message:?}");
2015        }
2016    }
2017
2018    /// A pragma line ends where the next line starts, so a macro that comes to nothing and was
2019    /// written first on that next line has to hand the line on rather than take it away. This
2020    /// is SQLite through mingw-w64's headers: `<stdarg.h>` leaves a `#pragma pack(pop)` behind
2021    /// it and `sqlite3.h` writes every declaration with `SQLITE_API` in front, which is empty.
2022    /// Without it the pragma swallows the declaration, the program is left without it, and the
2023    /// only thing said about any of it is that there was junk on the pragma.
2024    #[test]
2025    fn a_declaration_behind_an_empty_macro_is_not_eaten_by_the_pragma_above_it() {
2026        let result = run(
2027            &options(),
2028            concat!(
2029                "#pragma pack(push, 1)\n",
2030                "#pragma pack(pop)\n",
2031                "#define API\n",
2032                "API const char version[] = \"3.53.4\";\n",
2033                "const char *get(void) { return version; }\n",
2034            ),
2035        );
2036        assert!(result.messages.is_empty(), "{:?}", result.messages);
2037    }
2038
2039    /// The two typedef spellings of the 128 bit types. gcc offers them as keywords rather
2040    /// than as typedefs in a header, which is the only way a program that includes nothing at
2041    /// all can still use them, and Apple's `<mach/arm/_structs.h>` is one such program.
2042    #[test]
2043    fn the_wide_integer_answers_to_all_three_of_its_names() {
2044        let text = tast("__uint128_t a; __int128_t b; unsigned __int128 c;\n");
2045        assert!(text.contains("decl #0 a : unsigned __int128"), "{text}");
2046        assert!(text.contains("decl #1 b : __int128"), "{text}");
2047        assert!(text.contains("decl #2 c : unsigned __int128"), "{text}");
2048    }
2049
2050    #[test]
2051    fn every_conversion_the_language_performs_is_a_node_in_the_output() {
2052        // The point of a typed tree. The source has one operator and the output has the
2053        // widening that operator asked for, spelled out, so that nothing downstream has to
2054        // work out the conversion rules a second time.
2055        let text = tast("long f(int a, long b) { return a + b; }\n");
2056        assert!(text.contains("convert arithmetic"), "{text}");
2057    }
2058
2059    #[test]
2060    fn a_mistake_in_each_phase_reaches_the_caller_and_writes_no_tree() {
2061        for source in [
2062            "#error stop\n",
2063            "int f(void) { return 1 + ; }\n",
2064            "int f(void) { return undeclared; }\n",
2065        ] {
2066            let result = run(&options(), source);
2067            assert!(result.failed(), "expected this to fail:\n{source}");
2068            assert!(
2069                result.text().is_empty(),
2070                "a file that did not compile wrote a tree:\n{source}"
2071            );
2072        }
2073    }
2074
2075    #[test]
2076    fn one_undeclared_name_is_one_message_and_not_one_per_use() {
2077        // The poisoning rule from `spec/06-lexer-and-parser.md` section 6.8, seen from the
2078        // outside. Three uses of a name that was never declared, and the operators over them
2079        // say nothing at all.
2080        let result = run(&options(), "int f(void) { return nope + nope * nope; }\n");
2081        assert_eq!(result.errors, 1, "{:?}", result.messages);
2082    }
2083
2084    #[test]
2085    fn a_declaration_the_parser_skipped_does_not_become_an_undeclared_name_as_well() {
2086        // The reason the checking is skipped after a failed parse. The parser gave up on the
2087        // first line and there is no `x` in the tree, so a checker run over it would report
2088        // every use of `x` below as undeclared, which is a second message about one mistake.
2089        let result = run(&options(), "int x = ;\nint f(void) { return x; }\n");
2090        assert_eq!(result.errors, 1, "{:?}", result.messages);
2091    }
2092
2093    #[test]
2094    fn werror_turns_a_warning_into_an_error_in_the_count_and_in_the_word() {
2095        let source = "int f(void) { char c = 300; return c; }\n";
2096        let plain = run(&options(), source);
2097        assert_eq!(plain.errors, 0, "{:?}", plain.messages);
2098        assert_eq!(plain.messages.len(), 1, "expected a warning about the narrowed constant");
2099        assert!(!plain.text().is_empty(), "a warning is not a reason to write nothing");
2100
2101        let mut opts = options();
2102        opts.warnings_are_errors = true;
2103        let strict = run(&opts, source);
2104        assert!(strict.failed());
2105        assert!(strict.text().is_empty(), "and under -Werror it is a reason to write nothing");
2106        for message in &strict.messages {
2107            assert!(!message.contains("warning:"), "{message}");
2108        }
2109    }
2110
2111    #[test]
2112    fn w_drops_the_warning_before_werror_can_promote_it() {
2113        let source = "int f(void) { char c = 300; return c; }\n";
2114        let mut opts = options();
2115        opts.warnings = false;
2116        let quiet = run(&opts, source);
2117        assert_eq!(quiet.messages, Vec::<String>::new());
2118        assert_eq!(quiet.errors, 0);
2119        assert!(!quiet.text().is_empty(), "and the file still compiles");
2120
2121        // A build that passes both means it wants neither, and the order it wrote them in is not
2122        // something to make it think about.
2123        opts.warnings_are_errors = true;
2124        let both = run(&opts, source);
2125        assert_eq!(both.messages, Vec::<String>::new());
2126        assert!(!both.failed(), "-w -Werror is not an error about a warning nobody saw");
2127    }
2128
2129    #[test]
2130    fn the_dialect_reaches_the_keywords_and_the_checking() {
2131        // `typeof` is C23's and GNU's, so the same source is a declaration under one dialect
2132        // and a mistake under the other, which is the keyword table being built per dialect.
2133        let source = "typeof(1) x;\n";
2134        let mut opts = options();
2135        opts.std = Std::C23;
2136        opts.gnu_extensions = false;
2137        assert!(!run(&opts, source).failed(), "{:?}", run(&opts, source).messages);
2138
2139        opts.std = Std::C17;
2140        assert!(run(&opts, source).failed());
2141    }
2142
2143    #[test]
2144    fn asking_for_a_kind_that_is_not_written_yet_runs_the_front_end_and_writes_nothing() {
2145        let mut opts = options();
2146        opts.emit = EmitKind::Object;
2147        let result = run(&opts, "int x = 1;\n");
2148        assert!(!result.failed(), "{:?}", result.messages);
2149        assert!(result.text().is_empty());
2150        // And it still finds what the checking finds, so a later kind on a broken file is not
2151        // a silent success.
2152        assert!(run(&opts, "int f(void) { return undeclared; }\n").failed());
2153    }
2154
2155    /// The machine code of `source`, insisting that it compiled cleanly.
2156    fn mir(source: &str) -> String {
2157        let mut opts = options();
2158        opts.emit = EmitKind::MirFinal;
2159        let result = run(&opts, source);
2160        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
2161        result.text().to_owned()
2162    }
2163
2164    /// The whole compiler in one assertion, which is what this emit kind is for.
2165    ///
2166    /// C in, machine instructions out, every register a real one and every frame offset a
2167    /// number. Everything between the two is checked somewhere else, one pass at a time. What is
2168    /// checked here is that the passes are joined up and that the driver runs them.
2169    #[test]
2170    fn a_function_goes_from_c_to_instructions_with_real_registers_in_them() {
2171        let text = mir("int add(int a, int b) { return a + b; }\n");
2172        assert!(text.starts_with("mfunc @add {"), "{text}");
2173        assert!(text.contains("x64.add_rr_32"), "{text}");
2174        assert!(text.contains("x64.ret"), "{text}");
2175        // A virtual register is what the allocator was there to remove, so one left in the
2176        // output is the difference between code and something that looks like code.
2177        assert!(!text.contains('%'), "{text}");
2178    }
2179
2180    /// A declaration has no body, so there is nothing to generate for one and nothing is.
2181    #[test]
2182    fn a_function_with_no_body_produces_no_machine_function() {
2183        let text = mir("int g(int);\nint f(int a) { return g(a); }\n");
2184        assert_eq!(text.matches("mfunc @").count(), 1, "{text}");
2185        assert!(text.contains("mfunc @f {"), "{text}");
2186        assert!(text.contains("x64.call"), "{text}");
2187    }
2188
2189    /// Two functions come out in the order the module holds them, which is source order.
2190    #[test]
2191    fn every_definition_in_the_file_is_generated_and_they_keep_their_order() {
2192        let text = mir("int a(int x) { return x; }\nint b(int x) { return x; }\n");
2193        let first = text.find("mfunc @a").expect("the first function");
2194        let second = text.find("mfunc @b").expect("the second function");
2195        assert!(first < second, "{text}");
2196    }
2197
2198    /// The target reaches the back end, so the same C is different instructions on Windows.
2199    #[test]
2200    fn the_target_decides_which_convention_the_generated_code_follows() {
2201        let mut opts = options();
2202        opts.emit = EmitKind::MirFinal;
2203        let linux = run(&opts, "int f(int a) { return a; }\n").text().to_owned();
2204        assert!(linux.contains("$rdi"), "{linux}");
2205
2206        opts.target = "x86_64-pc-windows-msvc".parse::<Triple>().unwrap();
2207        let windows = run(&opts, "int f(int a) { return a; }\n").text().to_owned();
2208        assert!(windows.contains("$rcx"), "{windows}");
2209        assert!(!windows.contains("$rdi"), "{windows}");
2210    }
2211
2212    /// And it reaches the front end, where it decides what an anonymous member is.
2213    ///
2214    /// This is the shape `<objidl.h>` writes and the Windows headers are full of: the union inside
2215    /// `STGMEDIUM` closes with `} DUMMYUNIONNAME;`, and the macro expands to nothing unless the
2216    /// program defined `NONAMELESSUNION`, so what is left is a union with a tag and no name. On a
2217    /// Windows target that is an anonymous member, and reading it as a declaration of nothing
2218    /// drops it, which loses the names and the eight bytes the member takes up both.
2219    #[test]
2220    fn a_tagged_member_with_no_name_is_a_member_on_windows_and_nothing_on_linux() {
2221        let source = concat!(
2222            "struct S { union U { int i; void *p; }; unsigned long tymed; };\n",
2223            "int size(void) { return sizeof(struct S); }\n",
2224            "int f(struct S *s) { s->i = 1; return s->i; }\n",
2225        );
2226
2227        let mut opts = options();
2228        opts.target = "x86_64-pc-windows-gnu".parse::<Triple>().unwrap();
2229        let windows = run(&opts, source);
2230        assert!(windows.messages.is_empty(), "{:?}", windows.messages);
2231
2232        let linux = run(&options(), source);
2233        assert_eq!(linux.messages.len(), 3, "{:?}", linux.messages);
2234        assert!(linux.messages[0].contains("does not declare anything"), "{:?}", linux.messages);
2235
2236        // And the flag answers for either of them, so a program built for Linux against a header
2237        // written for Windows can be read the way the header meant it.
2238        let mut opts = options();
2239        opts.ms_extensions = Some(true);
2240        let asked = run(&opts, source);
2241        assert!(asked.messages.is_empty(), "{:?}", asked.messages);
2242    }
2243
2244    /// A target with no back end says so rather than generating something for another machine.
2245    #[test]
2246    fn a_target_this_has_no_back_end_for_is_reported_rather_than_generated() {
2247        let mut opts = options();
2248        opts.emit = EmitKind::MirFinal;
2249        opts.target = "aarch64-unknown-linux-gnu".parse::<Triple>().unwrap();
2250        let result = run(&opts, "int f(int a) { return a; }\n");
2251        assert!(result.failed());
2252        assert!(result.messages[0].contains("no back end for aarch64"), "{:?}", result.messages);
2253        assert!(result.text().is_empty());
2254    }
2255
2256    /// A construct the rule set does not reach yet is named, along with the function it is in.
2257    ///
2258    /// The message is about this compiler being unfinished rather than about the program, which
2259    /// is valid C either way, so it carries the note that says where the work is tracked. Both
2260    /// functions are attempted, so a file that is ahead of the back end in three places says so
2261    /// three times rather than one recompilation at a time.
2262    #[test]
2263    fn a_construct_the_back_end_cannot_reach_yet_is_reported_against_its_function() {
2264        let mut opts = options();
2265        opts.emit = EmitKind::MirFinal;
2266        let source = "void a(int n) { int v[n] __attribute__((aligned(32))); v[0] = 1; }\n\
2267                      void b(int n) { int v[n] __attribute__((aligned(32))); v[0] = 1; }\n";
2268        let result = run(&opts, source);
2269        assert!(result.failed());
2270        assert_eq!(result.messages.len(), 2, "{:?}", result.messages);
2271        assert!(result.messages[0].contains("cannot generate code for 'a'"), "{:?}", result);
2272        assert!(result.messages[0].contains("wants more alignment"), "{:?}", result);
2273        assert!(result.messages[1].contains("cannot generate code for 'b'"), "{:?}", result);
2274        assert!(result.text().is_empty());
2275    }
2276
2277    /// A variable length array walks its pages under the flag that says every page is touched.
2278    ///
2279    /// The pages the prologue takes are touched by the prologue. The pages the array takes are
2280    /// however many the size worked out to, so touching them is a loop written around the
2281    /// declaration rather than anything a prologue can do. What says the loop is there is the
2282    /// ordered comparison it ends each step with, which nothing else in a function writes, and the
2283    /// touch behind it. Without the flag the declaration is still the one subtraction it always was.
2284    #[test]
2285    fn a_variable_length_array_walks_its_pages_where_every_page_of_the_frame_is_to_be_touched() {
2286        let mut opts = options();
2287        opts.emit = EmitKind::MirFinal;
2288        let source = "void a(int n) { int v[n]; v[0] = 1; }\n";
2289        let plain = run(&opts, source);
2290        assert!(!plain.failed(), "{:?}", plain.messages);
2291        assert!(!plain.text().contains("cmp_set_a_64"), "{}", plain.text());
2292
2293        opts.stack_clash = true;
2294        let result = run(&opts, source);
2295        assert!(!result.failed(), "{:?}", result.messages);
2296        assert!(result.text().contains("cmp_set_a_64"), "{}", result.text());
2297        assert!(result.text().contains("or_mi_8"), "{}", result.text());
2298    }
2299
2300    /// An opcode the rule language has no word for is named anyway, and pointed at.
2301    ///
2302    /// The rule language's spelling is the better name when there is one, but an opcode it has
2303    /// no word for is exactly the opcode no rule lowers, so falling back to the opcode and the
2304    /// type is what makes the message say anything at all in the cases that happen. The span is
2305    /// the instruction's own, so the message lands on the line rather than on the file.
2306    ///
2307    /// The width of the float is what keeps the program refused. Everything else here is split into
2308    /// halves by `rucc_codegen::wide`, including the divisions and the conversions to a `float` and
2309    /// a `double`, which became calls into the compiler runtime. A `long double` is the eighty bit
2310    /// float on this target, the runtime has no conversion at that width because the back end has no
2311    /// register that holds one, which is tamnd/rucc#326, so a function converting to it is left with
2312    /// its wide values and reaches the selector the way every function of this width used to.
2313    #[test]
2314    fn an_opcode_with_no_name_in_the_rule_language_is_named_by_its_own_spelling() {
2315        let mut opts = options();
2316        opts.emit = EmitKind::MirFinal;
2317        let source =
2318            "long double f(int a) {\n  __int128 wide = a;\n  return (long double) wide;\n}\n";
2319        let result = run(&opts, source);
2320        assert!(result.failed());
2321        assert!(
2322            result.messages[0].contains("no rule lowers a `sext` producing a `i128`"),
2323            "{result:?}"
2324        );
2325        assert!(result.messages[0].contains(":2:"), "the line the widening is on: {result:?}");
2326        assert!(!result.messages[0].contains("this instruction"), "{result:?}");
2327    }
2328
2329    /// The note names the issue tracker, which is where a reader finds out whether it is known.
2330    #[test]
2331    fn the_note_on_unfinished_work_points_at_the_issues_rather_than_at_the_plan() {
2332        let mut opts = options();
2333        opts.emit = EmitKind::MirFinal;
2334        let source = "long double f(int a) { __int128 wide = a; return (long double) wide; }\n";
2335        let result = run(&opts, source);
2336        assert!(result.failed());
2337        let note = result.messages.iter().find(|line| line.contains("note:")).expect("a note");
2338        assert!(note.contains("https://github.com/tamnd/rucc/issues"), "{note}");
2339        assert!(!note.contains("spec/17-milestones.md"), "{note}");
2340    }
2341
2342    /// The two frame flags reach the frame, which is the only thing either of them does.
2343    #[test]
2344    fn the_frame_flags_on_the_command_line_reach_the_generated_frame() {
2345        let source = "int f(int a) { return a; }\n";
2346        assert!(!mir(source).contains("$rbp"), "a leaf needs no frame pointer by default");
2347
2348        let mut opts = options();
2349        opts.emit = EmitKind::MirFinal;
2350        opts.frame_pointer = true;
2351        let kept = run(&opts, source).text().to_owned();
2352        assert!(kept.contains("x64.push_64 $rbp"), "{kept}");
2353    }
2354
2355    /// The assembly of `source`, insisting that it compiled cleanly.
2356    fn asm(source: &str) -> String {
2357        let mut opts = options();
2358        opts.emit = EmitKind::Asm;
2359        let result = run(&opts, source);
2360        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
2361        result.text().to_owned()
2362    }
2363
2364    /// `-S`, which is the same compiler as the kind above it with a different last step.
2365    ///
2366    /// What the assembly says is checked in `rucc-asm`, one instruction at a time and against the
2367    /// target's own description of what an instruction is. What is checked here is that a C file
2368    /// goes all the way to a listing an assembler would take, which means the directives around
2369    /// the function as well as the instructions in it.
2370    #[test]
2371    fn a_function_goes_from_c_to_assembly_an_assembler_would_take() {
2372        let text = asm("int add(int a, int b) { return a + b; }\n");
2373        assert!(text.contains("\t.globl\tadd\n"), "{text}");
2374        assert!(text.contains("\t.type\tadd, @function\n"), "{text}");
2375        assert!(text.contains("\nadd:\n"), "{text}");
2376        assert!(text.contains("\taddl\t"), "{text}");
2377        assert!(text.contains("\tret\n"), "{text}");
2378        assert!(text.contains("\t.size\tadd, .-add\n"), "{text}");
2379        // Without this the stack the program runs on is executable, which is not a default
2380        // anybody chose and is not a thing a reader would notice missing.
2381        assert!(text.contains(".note.GNU-stack"), "{text}");
2382    }
2383
2384    /// A call through a function pointer, which is a different instruction from a call to a name.
2385    ///
2386    /// Both are in the one function on purpose. What is being read is that the two calls are told
2387    /// apart all the way down: one carries a name the linker resolves and one carries a register,
2388    /// and neither turns into the other on the way.
2389    #[test]
2390    fn a_call_through_a_function_pointer_goes_through_the_register_it_is_in() {
2391        let text = asm("int g(int);\nint f(int (*p)(int), int a) { return p(a) + g(a); }\n");
2392        assert!(text.contains("\tcall\t*%"), "{text}");
2393        assert!(text.contains("\tcall\tg\n"), "{text}");
2394        // The address arrived in the first argument register and the argument the call passes has
2395        // to end up there, so the two cannot be the same register and the compiler has to have
2396        // moved one of them.
2397        assert!(text.contains("%rdi"), "{text}");
2398    }
2399
2400    /// A name at file scope, which is the one address a function cannot compute for itself. The
2401    /// `lea` that computes it is folded into the load that reads through it, so what is left to
2402    /// read is the addressing mode, which is where the instruction pointer shows up.
2403    #[test]
2404    fn the_address_of_a_global_is_read_from_the_instruction_pointer() {
2405        let text = asm("extern int counter;\nint f(void) { return counter; }\n");
2406        assert!(text.contains("\tmovl\tcounter(%rip), %eax\n"), "{text}");
2407    }
2408
2409    /// Every comparison a branch can be on, which the machine jumps on without keeping a byte.
2410    ///
2411    /// Ten conditions, and each of them comes out as its opposite because the block falls into the
2412    /// arm the comparison is true for and jumps to the other one. That is the half of this most
2413    /// worth pinning: a jump on the condition rather than on its opposite compiles, encodes and
2414    /// runs, and gets every one of these ten functions backwards. The unsigned four and the signed
2415    /// four are separate for the same reason, since `jl` where `jb` was meant is a program that
2416    /// works until an address is above two gigabytes.
2417    #[test]
2418    fn a_branch_on_a_comparison_jumps_on_the_opposite_of_what_it_compared() {
2419        let arms = "return 1; return 2;";
2420        let signed = [("==", "jne"), ("!=", "je"), ("<", "jge"), ("<=", "jg"), (">", "jle")];
2421        for (operator, jump) in signed.into_iter().chain([(">=", "jl")]) {
2422            let text = asm(&format!("int f(int a, int b) {{ if (a {operator} b) {arms} }}\n"));
2423            assert!(
2424                text.contains(&format!("\tcmpl\t%esi, %edi\n\t{jump}\t")),
2425                "{operator}: {text}"
2426            );
2427            assert!(!text.contains("\tset"), "{operator}: {text}");
2428            assert!(!text.contains("\ttest"), "{operator}: {text}");
2429        }
2430        let unsigned = [("<", "jae"), ("<=", "ja"), (">", "jbe"), (">=", "jb")];
2431        for (operator, jump) in unsigned {
2432            let source =
2433                format!("int f(unsigned a, unsigned b) {{ if (a {operator} b) {arms} }}\n");
2434            let text = asm(&source);
2435            assert!(
2436                text.contains(&format!("\tcmpl\t%esi, %edi\n\t{jump}\t")),
2437                "{operator}: {text}"
2438            );
2439        }
2440
2441        // And against a constant, which is four comparisons in five and is where the saving
2442        // mostly is, since the byte that goes was the only reason the constant was in a register.
2443        let text = asm("int f(int a) { if (a < 7) return 1; return 2; }\n");
2444        assert!(text.contains("\tcmpl\t$7, %edi\n\tjge\t"), "{text}");
2445    }
2446
2447    /// The comparison whose answer is a value rather than a branch, which keeps its byte.
2448    ///
2449    /// The one that goes is the byte nothing but the branch reads. A comparison the program asked
2450    /// for the answer of is not that, and there is no branch behind it to fold into in any case,
2451    /// so this is here to say that what was taken out was taken out of one place and not two.
2452    #[test]
2453    fn a_comparison_whose_answer_the_program_wanted_still_writes_a_byte() {
2454        let text = asm("int f(int a, int b) { return a < b; }\n");
2455        assert!(text.contains("\tsetl\t"), "{text}");
2456    }
2457
2458    /// The same source at `-O2`, which is where the optimizer's passes are in the list.
2459    fn optimized(source: &str) -> String {
2460        let mut opts = options();
2461        opts.emit = EmitKind::Asm;
2462        opts.opt_level = rucc_session::OptLevel::O2;
2463        let result = run(&opts, source);
2464        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
2465        result.text().to_owned()
2466    }
2467
2468    /// A dense `switch` whose arms are a function of the label, which is arithmetic.
2469    ///
2470    /// Sixteen labels, and the arm for label `k` gives `k + 1`. What came out of this was a
2471    /// comparison and a jump for every one of them, which is tamnd/rucc#728. What comes out now is
2472    /// one comparison and one addition, and the count is the whole of the claim: it does not grow
2473    /// with the number of labels, so sixteen and a hundred and sixty compile to the same thing.
2474    ///
2475    /// The comparison is unsigned because the range check is the label minus the lowest one, which
2476    /// is a count and not a number the program wrote.
2477    #[test]
2478    fn a_switch_whose_arms_are_a_function_of_the_label_is_a_range_check_and_arithmetic() {
2479        let arms: String =
2480            (0..16).map(|k| format!("case {k}: return {};", k + 1)).collect::<Vec<_>>().join(" ");
2481        let text = optimized(&format!("int f(int x) {{ switch (x) {{ {arms} }} return 0; }}\n"));
2482        assert!(text.contains("\tcmpl\t$15, %edi\n\tja\t"), "{text}");
2483        assert!(text.contains("\taddl\t$1, %edi"), "{text}");
2484        assert_eq!(text.matches("\tcmp").count(), 1, "{text}");
2485    }
2486
2487    /// The same `switch` with one arm off the line, which keeps every comparison it had.
2488    ///
2489    /// The answers being a line is what licenses the range check, since a range check answers for
2490    /// every label in the range at once. One label whose arm disagrees is a label the check would
2491    /// answer wrongly, so this is here to say that the pass is reading the arms and not counting
2492    /// the labels.
2493    #[test]
2494    fn a_dense_switch_whose_arms_are_not_a_line_keeps_its_comparisons() {
2495        let arms: String = (0..16)
2496            .map(|k| format!("case {k}: return {};", if k == 9 { 100 } else { k + 1 }))
2497            .collect::<Vec<_>>()
2498            .join(" ");
2499        let text = optimized(&format!("int f(int x) {{ switch (x) {{ {arms} }} return 0; }}\n"));
2500        assert!(text.matches("\tcmp").count() > 1, "{text}");
2501    }
2502
2503    /// A conversion whose operand the optimizer turned into a constant, which is the whole of what
2504    /// `rucc_opt::fold` does with floating point.
2505    ///
2506    /// The cast is not a constant expression, so the front end leaves it alone and the pipeline is
2507    /// what has to see it. Load forwarding turns the local back into the constant that was stored
2508    /// into it, and the conversion then has an `fconst` in front of it. What came out before was
2509    /// the sixty four bit pattern moved into a register, moved into an `xmm`, and a `cvttsd2si`.
2510    #[test]
2511    fn a_conversion_from_a_constant_double_is_the_number_it_converts_to() {
2512        let text = optimized("int f(void) { double d = 2.75; return (int) d; }\n");
2513        assert!(text.contains("movl\t$2, %eax"), "{text}");
2514        assert!(!text.contains("cvttsd2si"), "{text}");
2515    }
2516
2517    /// A slot of a `const` table read at an index the optimizer works out, which is what
2518    /// `rucc_opt::image` is for.
2519    ///
2520    /// The subscript is not a constant expression and the front end does not fold it. What it
2521    /// writes is the index sign extended, multiplied by four and added to the address of the
2522    /// table, so the offset only exists once `fold` has run and the load only folds after that.
2523    /// What came out before was a `movl t+8(%rip), %eax`.
2524    #[test]
2525    fn a_slot_of_a_read_only_table_is_the_value_the_table_holds() {
2526        let text =
2527            optimized("static const int t[4] = {10, 20, 30, 40};\nint f(void) { return t[2]; }\n");
2528        assert!(text.contains("movl\t$30, %eax"), "{text}");
2529        assert!(!text.contains("t(%rip)"), "{text}");
2530    }
2531
2532    /// A byte of a string literal, which is the same fold reading literal bytes rather than the
2533    /// scalars an `int` array is written as.
2534    #[test]
2535    fn a_byte_of_a_read_only_string_is_the_byte_the_string_spells() {
2536        let text = optimized("static const char s[] = \"abc\";\nint f(void) { return s[1]; }\n");
2537        assert!(text.contains("movl\t$98, %eax"), "{text}");
2538    }
2539
2540    /// A global something can write to, which is the condition the fold turns on and therefore
2541    /// the one worth a test of its own. Nothing here is `const`, so the store in `g` could be the
2542    /// store that ran last and the load has to happen.
2543    #[test]
2544    fn a_table_that_is_not_read_only_keeps_its_load() {
2545        let text = optimized(
2546            "static int t[4] = {10, 20, 30, 40};\nvoid g(int x) { t[2] = x; }\nint f(void) { return t[2]; }\n",
2547        );
2548        assert!(!text.contains("movl\t$30, %eax"), "{text}");
2549    }
2550
2551    /// `gcc.c-torture/execute/20030216-1.c`, which is the program the whole of this is for.
2552    ///
2553    /// It calls a function nothing defines, guarded by a condition the optimizer is meant to prove
2554    /// false, so the program links exactly when the call has been folded away. Getting there is
2555    /// three folds standing on each other: the load of the `const double`, the conversion of it to
2556    /// an `int`, and the comparison against one.
2557    #[test]
2558    fn a_call_guarded_by_a_condition_a_read_only_object_settles_is_not_emitted() {
2559        let text = optimized(
2560            "void link_error(void);\nconst double one = 1.0;\nint main(void) { if ((int) one != 1) link_error(); return 0; }\n",
2561        );
2562        assert!(!text.contains("call\tlink_error"), "{text}");
2563    }
2564
2565    /// A cast between a pointer and an integer as wide as one, which is every one C writes here.
2566    #[test]
2567    fn a_cast_between_a_pointer_and_an_integer_leaves_the_value_where_it_is() {
2568        let text = asm("long f(void *p) { return (long)p; }\n");
2569        // Every instruction in the body is a full width move or the return. The copies are the
2570        // allocator taking no hints, and what matters here is what is not among them: nothing
2571        // narrows the value and nothing widens it again, which is what a cast that did something
2572        // would look like.
2573        for line in text.lines().filter(|line| line.starts_with('\t') && !line.contains('.')) {
2574            let mnemonic = line.split_whitespace().next().unwrap_or("");
2575            assert!(matches!(mnemonic, "movq" | "ret"), "{line} in\n{text}");
2576        }
2577    }
2578
2579    /// The arguments past the sixth arrive in the caller's memory rather than in a register, and
2580    /// where that memory is depends on what the prologue did, so this is checked at the end of the
2581    /// pipeline rather than in the middle of it.
2582    #[test]
2583    fn an_argument_past_the_last_register_is_read_out_of_the_caller_s_stack() {
2584        let six = "long a, long b, long c, long d, long e, long f";
2585        let text = asm(&format!("long f({six}, long g, long h) {{ return g + h; }}\n"));
2586
2587        // Nothing is pushed and no frame is taken, so the only thing between the stack pointer and
2588        // the caller's arguments is the return address the call pushed. Which is where gcc 16.2.0
2589        // reads them from too, at `-O0`, though it reads them in three instructions where this
2590        // reads them in two: the second read is the addition's own memory operand, which is
2591        // `rucc_codegen::combine`, and the offset in it is the one the frame layout wrote into the
2592        // load before the two were put together.
2593        assert!(text.contains("\tmovq\t8(%rsp), "), "{text}");
2594        assert!(text.contains("\taddq\t16(%rsp), "), "{text}");
2595
2596        // A narrower one is read at its own width, because the bits above it are bits the
2597        // convention says nothing about, and one in the other register file with the other file's
2598        // instruction.
2599        let narrow = asm(&format!("int f({six}, int g) {{ return g; }}\n"));
2600        assert!(narrow.contains("\tmovl\t8(%rsp), "), "{narrow}");
2601        let eight =
2602            "double a, double b, double c, double d, double e, double f, double g, double h";
2603        let float = asm(&format!("double f({eight}, double i) {{ return i; }}\n"));
2604        assert!(float.contains("\tmovsd\t8(%rsp), "), "{float}");
2605    }
2606
2607    /// The other end of the same thing. What the caller writes is at the stack pointer, because
2608    /// that is the bottom of its frame and the bottom of its frame is where the callee looks.
2609    #[test]
2610    fn a_call_writes_the_arguments_with_no_register_left_at_the_stack_pointer() {
2611        let six = "1, 2, 3, 4, 5, 6";
2612        let decl = "long g(long, long, long, long, long, long, long, long);\n";
2613        let text = asm(&format!("{decl}long f(void) {{ return g({six}, 7, 8); }}\n"));
2614
2615        assert!(text.contains("\tmovq\t%"), "{text}");
2616        assert!(text.contains(", (%rsp)\n"), "{text}");
2617        assert!(text.contains(", 8(%rsp)\n"), "{text}");
2618        // And it reserved the bytes it wrote into, so nothing else in the frame is on top of them.
2619        assert!(text.contains("\tsubq\t$"), "{text}");
2620
2621        // A narrower one is written at its own width, matching what the callee reads it back with.
2622        let narrow = "int g(int, int, int, int, int, int, int);\n";
2623        let text = asm(&format!("{narrow}int f(void) {{ return g({six}, 7); }}\n"));
2624        assert!(text.contains("\tmovl\t%"), "{text}");
2625        assert!(text.contains(", (%rsp)\n"), "{text}");
2626    }
2627
2628    /// The count a variadic callee on this convention reads is a count of vector registers, so a
2629    /// float that ran out of them and went to memory is not in it.
2630    #[test]
2631    fn a_variadic_call_counts_registers_and_not_arguments() {
2632        let nine = "1., 2., 3., 4., 5., 6., 7., 8., 9.";
2633        let decl = "int g(int, ...);\n";
2634        let text = asm(&format!("{decl}int f(void) {{ return g(0, {nine}); }}\n"));
2635
2636        assert!(text.contains("\tmovl\t$8, "), "eight registers, not nine: {text}");
2637        assert!(text.contains("\tmovsd\t%"), "{text}");
2638        assert!(text.contains(", (%rsp)\n"), "{text}");
2639    }
2640
2641    /// The callee's half of the same convention. Every argument register it was handed is written
2642    /// into its frame on the way in, because which of them hold anything is a thing only the caller
2643    /// knew, and the ones the signature does name are left out because `va_start` sets the offsets
2644    /// past them and nothing ever reads their slots.
2645    #[test]
2646    fn a_variadic_function_writes_the_argument_registers_it_was_handed_into_its_frame() {
2647        let body =
2648            "__builtin_va_list ap; __builtin_va_start(ap, n); __builtin_va_end(ap); return n;";
2649        let text = asm(&format!("int f(int n, ...) {{ {body} }}\n"));
2650
2651        // Five general purpose registers and eight vector ones, since the one parameter the
2652        // signature names took the first of the six.
2653        let stores = |mnemonic: &str| text.matches(&format!("\t{mnemonic}\t%")).count();
2654        assert!(text.contains(", 8(%r"), "the second slot, not the first: {text}");
2655        assert!(!text.contains(", 0(%r"), "{text}");
2656        // All sixteen bytes of each vector register, which is what gcc writes and what a `va_arg`
2657        // of a `_Float128` reads back, so the mnemonic is the one that moves a whole register.
2658        assert_eq!(stores("movaps"), 8, "every vector register: {text}");
2659        assert_eq!(stores("movsd"), 0, "and the whole of each one: {text}");
2660
2661        // And the area is one of the function's own stack objects, so the frame holds it.
2662        assert!(text.contains("\tsubq\t$"), "{text}");
2663    }
2664
2665    /// What `va_start` writes is the four fields of the list, and the two numbers among them are
2666    /// where the arguments the signature names left the walk over each file's registers.
2667    #[test]
2668    fn va_start_writes_the_four_fields_the_psabi_describes() {
2669        let start = "__builtin_va_list ap; __builtin_va_start(ap, d);";
2670        let params = "int a, int b, int c, double d";
2671        let text = asm(&format!("int f({params}, ...) {{ {start} return a; }}\n"));
2672
2673        // Three integers took three of the six general purpose registers, and one double took one
2674        // of the eight vector ones, so the walk starts at twenty four bytes into the first half and
2675        // sixteen bytes into the second, which begins at forty eight.
2676        assert!(text.contains("	movl	$24, "), "{text}");
2677        assert!(text.contains("	movl	$64, "), "{text}");
2678        // The other two fields are addresses rather than numbers, so each is stored as a word and
2679        // each is a `lea` away. One of them reaches above the frame, which is where the caller's
2680        // arguments are and is the only thing in this function that is not below the stack pointer.
2681        assert!(text.contains(", 8(%r"), "{text}");
2682        assert!(text.contains(", 16(%r"), "{text}");
2683        let frame: u32 = text
2684            .lines()
2685            .find_map(|line| line.trim().strip_prefix("subq	$")?.split(',').next()?.parse().ok())
2686            .expect("a variadic function takes a frame for the save area");
2687        let above = |line: &str| {
2688            let at: u32 = line.trim().strip_prefix("leaq	")?.split('(').next()?.parse().ok()?;
2689            Some(at > frame)
2690        };
2691        assert!(text.lines().filter_map(above).any(|it| it), "{frame}: {text}");
2692    }
2693
2694    /// A `va_arg` is a branch on whether the argument it wants is still in the save area, and which
2695    /// of the two halves it walks is the type's answer.
2696    #[test]
2697    fn va_arg_branches_on_whether_the_argument_is_still_in_the_save_area() {
2698        let read = "__builtin_va_list ap; __builtin_va_start(ap, n);";
2699        let ints = format!("int f(int n, ...) {{ {read} return __builtin_va_arg(ap, int); }}\n");
2700        let text = asm(&ints);
2701
2702        // The last general purpose slot begins at forty, so an offset above it is an argument the
2703        // caller left in its own memory instead.
2704        assert!(text.contains("$40, "), "{text}");
2705        assert!(text.contains("	cmpl	"), "{text}");
2706        // The jump is the unsigned one, since an offset is a count of bytes. It is the opposite
2707        // of the comparison the front end wrote, because the block falls into the half taken when
2708        // the argument is still in the save area and jumps to the other one.
2709        assert!(text.contains("	ja	"), "{text}");
2710
2711        let arg = "__builtin_va_arg(ap, double)";
2712        let text = asm(&format!("double f(int n, ...) {{ {read} return {arg}; }}\n"));
2713        assert!(text.contains("$160, "), "the last vector slot: {text}");
2714    }
2715
2716    /// A structure assigned is a copy of a known size, and a copy of a known size is a run of
2717    /// moves rather than a call to a library this compiler has no way to reach yet.
2718    #[test]
2719    fn a_structure_assignment_is_a_move_for_each_word_of_it() {
2720        let decl = "struct pair { long a, b; };\n";
2721        let body = "struct pair p = *q; return p.a + p.b;";
2722        let text = asm(&format!("{decl}long f(struct pair *q) {{ {body} }}\n"));
2723
2724        assert!(!text.contains("memcpy"), "nothing calls the library: {text}");
2725        assert!(!text.contains("\tcall"), "{text}");
2726        // Sixteen bytes aligned to eight is two words, and each is a load and a store.
2727        assert!(text.matches("\tmovq\t").count() >= 4, "two words each way: {text}");
2728    }
2729
2730    /// A word is as wide as the object is aligned to and no wider, so a character array is copied
2731    /// a byte at a time and a structure of longs eight bytes at a time.
2732    #[test]
2733    fn how_wide_a_word_of_a_copy_is_follows_the_alignment() {
2734        let decl = "struct bytes { char a[8]; };\n";
2735        let body = "struct bytes p = *q; return p.a[0];";
2736        let text = asm(&format!("{decl}int f(struct bytes *q) {{ {body} }}\n"));
2737
2738        // Eight bytes aligned to one is eight words, and each is a load and a store.
2739        assert!(text.matches("\tmovb\t").count() >= 16, "a byte at a time: {text}");
2740    }
2741
2742    /// What an initialiser does not name is zero, which the front end writes as a fill and this
2743    /// writes as the byte spread across each word.
2744    #[test]
2745    fn the_part_of_an_initialiser_that_names_nothing_is_stored_as_zero() {
2746        let decl = "struct wide { long a, b, c; };\n";
2747        let text = asm(&format!("{decl}long f(void) {{ struct wide w = {{ 7 }}; return w.c; }}\n"));
2748
2749        assert!(!text.contains("memset"), "nothing calls the library: {text}");
2750        assert!(text.contains("\tmovq\t$0, ") || text.contains("$0, %"), "the zero: {text}");
2751    }
2752
2753    /// A copy too large to be worth unrolling is a call to the runtime, which is the C library on
2754    /// a hosted target and `rucc-builtins` on a freestanding one.
2755    #[test]
2756    fn a_copy_too_large_to_unroll_calls_the_runtime() {
2757        let decl = "struct huge { char a[4096]; };\n";
2758        let mut opts = options();
2759        opts.emit = EmitKind::Asm;
2760        let source = format!("{decl}void f(struct huge *p, struct huge *q) {{ *p = *q; }}\n");
2761        let result = run(&opts, &source);
2762        assert!(!result.failed(), "{:?}", result.messages);
2763        let text = result.text();
2764        assert!(text.contains("call") && text.contains("memcpy"), "{text}");
2765        // The size in the register the convention passes the third argument in, which is what
2766        // says the call was built from the convention and not from the shape of the IR.
2767        assert!(text.contains("4096"), "the size travels: {text}");
2768    }
2769
2770    /// And an object passed by value with more words in it than that is the same call again,
2771    /// written in front of the call the object is an argument of.
2772    ///
2773    /// The copy is one the caller owes the callee, since the callee is free to write to what it
2774    /// was handed, so it is not an optimization that the size decides but the only way the call
2775    /// can be made at all.
2776    #[test]
2777    fn a_structure_too_large_to_unroll_is_copied_into_the_argument_area_by_the_runtime() {
2778        let decl = "struct huge { char a[4096]; };\nint take(struct huge);\n";
2779        let text = asm(&format!("{decl}int f(struct huge *p) {{ return take(*p); }}\n"));
2780
2781        let copy = text.find("call\tmemcpy").expect("the copy");
2782        let call = text.find("call\ttake").expect("the call");
2783        assert!(copy < call, "the copy comes first: {text}");
2784        // Into the bottom of the outgoing area, which is where the stack pointer already is, and
2785        // with the size in the register the convention passes the third argument in.
2786        assert!(text.contains("leaq\t(%rsp), %rdi"), "the destination: {text}");
2787        assert!(text.contains("$4096, %edx"), "the size: {text}");
2788    }
2789
2790    /// A frame that had to force its own alignment cannot say how far away the caller's stack
2791    /// pointer was, so it reaches back through the frame pointer instead.
2792    #[test]
2793    fn a_realigned_frame_reads_them_through_the_frame_pointer() {
2794        let six = "long a, long b, long c, long d, long e, long f";
2795        let body = "_Alignas(32) long wide[4]; wide[0] = g; return wide[0];";
2796        let text = asm(&format!("long f({six}, long g) {{ {body} }}\n"));
2797
2798        // The frame pointer is saved and pointed at where it was saved before the alignment is
2799        // forced, so the caller's arguments stay a constant distance from it: one word for the
2800        // saved frame pointer and one for the return address.
2801        assert!(text.contains("\tandq\t$-32, %rsp"), "{text}");
2802        assert!(text.contains("\tmovq\t16(%rbp), "), "{text}");
2803        assert!(!text.contains("\tmovq\t16(%rsp), "), "{text}");
2804    }
2805
2806    /// The object format decides the directives, and the target decides the object format.
2807    #[test]
2808    fn the_target_decides_how_the_assembly_is_spelled() {
2809        let mut opts = options();
2810        opts.emit = EmitKind::Asm;
2811        opts.target = "x86_64-apple-darwin".parse::<Triple>().unwrap();
2812        let text = run(&opts, "int f(void) { return 0; }\n").text().to_owned();
2813        assert!(text.contains("__TEXT,__text"), "{text}");
2814        assert!(text.contains("\n_f:\n"), "{text}");
2815        assert!(!text.contains(".note.GNU-stack"), "{text}");
2816    }
2817
2818    /// The object file of `source`, insisting that it compiled cleanly.
2819    fn obj(source: &str) -> Vec<u8> {
2820        let mut opts = options();
2821        opts.emit = EmitKind::Object;
2822        let result = run(&opts, source);
2823        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
2824        match result.artifact {
2825            Artifact::Object { bytes, .. } => bytes,
2826            other => panic!("expected an object, got {other:?}"),
2827        }
2828    }
2829
2830    /// `-c`, which is the last step of the three the back end can end with.
2831    ///
2832    /// What is in the file is checked in `rucc-object`, a field at a time. What is checked here is
2833    /// that a C file goes all the way to one, which is the whole compiler in one line and the
2834    /// thing that stops working when a layer between them changes its mind about something.
2835    #[test]
2836    fn a_function_goes_from_c_to_an_object_a_linker_would_take() {
2837        let bytes = obj("int add(int a, int b) { return a + b; }\n");
2838        assert_eq!(&bytes[..4], b"\x7fELF", "an object file starts by saying it is one");
2839        let text = asm("int add(int a, int b) { return a + b; }\n");
2840        assert!(
2841            text.contains("\taddl\t"),
2842            "and the listing of it is the same instructions:\n{text}"
2843        );
2844    }
2845
2846    /// A variable this file defines, which is what a reference to one has to resolve against.
2847    #[test]
2848    fn a_variable_goes_from_c_to_the_section_it_belongs_in() {
2849        let text = asm("int counter = 42;\nstatic int hidden;\nconst int fixed = 7;\n");
2850        assert!(text.contains("\t.data\n\t.globl\tcounter\n"), "{text}");
2851        assert!(text.contains("\ncounter:\n\t.long\t42\n"), "{text}");
2852        assert!(text.contains("\t.size\tcounter, .-counter\n"), "{text}");
2853        // A zeroed variable carries its size and none of its bytes, and a `static` one is not
2854        // announced to the linker at all, which is the whole of what `static` means here.
2855        assert!(text.contains("\t.bss\n\t.p2align\t2\n"), "{text}");
2856        assert!(text.contains("\nhidden:\n\t.space\t4\n"), "{text}");
2857        assert!(!text.contains(".globl\thidden"), "{text}");
2858        // Nothing writes through it, so it goes in a page the loader can map read only and every
2859        // process running the program can share.
2860        assert!(text.contains("\t.section\t.rodata\n"), "{text}");
2861    }
2862
2863    /// A bit-field with a value in it, which is written as the bytes the value lands in.
2864    ///
2865    /// The interesting one is the field whose lowest byte is zero. The bytes a bit-field
2866    /// initializer makes are put together first and then taken back out as the run they make,
2867    /// and taking them out starts at the byte the field starts at, so a zero byte at the front
2868    /// used to end the object up in `.bss` with the rest of its value thrown away.
2869    #[test]
2870    fn a_bit_field_initializer_writes_every_byte_of_the_value_and_not_only_the_ones_that_are_set() {
2871        let text = asm("struct s { unsigned f : 20; } x = { 0x12300 };\n");
2872        assert!(text.contains("\t.data\n"), "there is something to write: {text}");
2873        assert!(text.contains("\nx:\n\t.ascii\t\"\\000#\\001\"\n"), "and it is the value: {text}");
2874
2875        // Two fields, the first of them zero, which is the same thing said with the zero byte
2876        // inside the run rather than at the front of it.
2877        let text = asm("struct s { unsigned a : 8; unsigned b : 8; } x = { 0, 3 };\n");
2878        assert!(text.contains("\nx:\n\t.ascii\t\"\\000\\003\"\n"), "{text}");
2879
2880        // Wider than an `int`, which is the same code and is worth saying because the value no
2881        // longer fits in the thirty two bits a bit-field used to be read at.
2882        let text = asm("struct s { unsigned long long f : 40; } x = { 0x100000 };\n");
2883        assert!(text.contains("\nx:\n\t.ascii\t\"\\000\\000\\020\"\n\t.space\t5\n"), "{text}");
2884
2885        // Nothing in it, which still costs no bytes in the file.
2886        let text = asm("struct s { unsigned f : 20; } x = { 0 };\n");
2887        assert!(text.contains("\t.bss\n"), "an object of zeroes is zeroes: {text}");
2888        assert!(text.contains("\nx:\n\t.space\t4\n"), "{text}");
2889    }
2890
2891    /// A string literal, which is a variable the program never named.
2892    #[test]
2893    fn a_string_literal_is_a_variable_with_a_name_no_program_could_write() {
2894        let text = asm("const char *f(void) { return \"hi\"; }\n");
2895        assert!(text.contains("\t.ascii\t\"hi\\000\"\n"), "{text}");
2896        assert!(text.contains("\t.section\t.rodata\n"), "{text}");
2897        let label = text
2898            .lines()
2899            .find(|line| line.starts_with(".Lstr"))
2900            .unwrap_or_else(|| panic!("a label for the literal in\n{text}"));
2901        assert!(!text.contains(&format!(".globl\t{}", label.trim_end_matches(':'))), "{text}");
2902    }
2903
2904    /// A variable holding the address of another one, which is the only hole an image has in it.
2905    #[test]
2906    fn an_address_in_an_initializer_is_left_to_the_linker() {
2907        let source = "int counter;\nint *p = &counter;\n";
2908        let text = asm(source);
2909        assert!(text.contains("\np:\n\t.quad\tcounter\n"), "{text}");
2910        // And in the object it is eight zero bytes and a relocation, which is what the two paths
2911        // being one description is for.
2912        let bytes = obj(source);
2913        assert!(bytes.windows(8).any(|w| w == b"counter\0"), "the object has to name it");
2914    }
2915
2916    /// A const table of function pointers, which is the shape that made SQLite link with a warning.
2917    ///
2918    /// The table is const so nothing in the program writes it, but the addresses in it are not
2919    /// numbers a link knows, so the loader writes it once at startup. Putting it in `.rodata`
2920    /// leaves a relocation in a section that is never writable, and what the linker does about
2921    /// that is set `DT_TEXTREL` on the whole image and say so. `.data.rel.ro` is writable for
2922    /// exactly as long as the loader is writing it and read only afterwards, which is what the
2923    /// program asked for in the first place.
2924    #[test]
2925    fn a_constant_holding_an_address_goes_in_the_section_the_loader_may_write_once() {
2926        // Both names are `static` and both are defined here, so nothing else can be the one that
2927        // defines them and the linker may lay the table out in the first pages of the segment.
2928        let text = asm("static void a(void) {}\nstatic void b(void) {}\n\
2929             struct m { void (*x)(void); void (*y)(void); };\n\
2930             const struct m t = { a, b };\n");
2931        assert!(text.contains("\t.section\t.data.rel.ro.local,\"aw\",@progbits\n"), "{text}");
2932        assert!(text.contains("\nt:\n\t.quad\ta\n\t.quad\tb\n"), "{text}");
2933
2934        // One name this file only declares is enough to lose the `.local` half, because a name the
2935        // link resolves from somewhere else is one another object may turn out to define.
2936        let text =
2937            asm("void a(void);\nstruct m { void (*x)(void); };\nconst struct m t = { a };\n");
2938        assert!(text.contains("\t.section\t.data.rel.ro,\"aw\",@progbits\n"), "{text}");
2939
2940        // And a constant with no address in it stays exactly where it was.
2941        let text = asm("const int fixed = 7;\n");
2942        assert!(text.contains("\t.section\t.rodata\n"), "{text}");
2943    }
2944
2945    /// A thread-local variable, which is the whole of one: the storage and the way to reach it.
2946    ///
2947    /// The two halves are in one test on purpose. Either one alone is worse than neither: a
2948    /// definition with no way to reach it is a variable nothing can read, and a reference with no
2949    /// definition behind it is the bug this pair was written to prevent, where a thread-local is
2950    /// read as though it were an ordinary global and every thread quietly shares one copy.
2951    #[test]
2952    fn a_thread_local_variable_is_storage_a_thread_gets_a_copy_of_and_an_offset_into_it() {
2953        let text = asm("_Thread_local int x = 1;\nint read(void) { return x; }\n");
2954        // The storage: the section the loader makes a copy of for every thread, and the symbol
2955        // type that makes a linker refuse an ordinary relocation aimed at it.
2956        assert!(text.contains("\t.section\t.tdata,\"awT\",@progbits\n"), "{text}");
2957        assert!(text.contains("\t.type\tx, @tls_object\n"), "{text}");
2958        // The way to reach it: how far into a thread's block it sits, out of the table, plus where
2959        // this thread's block is, out of the segment register.
2960        assert!(text.contains("x@GOTTPOFF(%rip)"), "{text}");
2961        assert!(text.contains("%fs:0"), "{text}");
2962    }
2963
2964    /// The second half of that on its own, which is what a program asks for when the number it
2965    /// wants is the thread rather than anything in it.
2966    ///
2967    /// rpmalloc writes this to find its per thread cache, and it is the whole of what stood
2968    /// between that library and a build. gcc 16 writes the same one instruction.
2969    #[test]
2970    fn the_address_of_this_thread_s_own_storage_is_read_out_of_the_segment_register() {
2971        let text = asm("void *here(void) { return __builtin_thread_pointer(); }\n");
2972        assert!(text.contains("movq\t%fs:0, "), "{text}");
2973        // No table slot and no addition, because there is no variable to find inside the block.
2974        assert!(!text.contains("GOTTPOFF"), "{text}");
2975    }
2976
2977    /// The four hints and the one thing that decides between them, which is the locality.
2978    ///
2979    /// A prefetch promises nothing, so what is checked here is the instruction rather than any
2980    /// effect: the program runs the same whichever of the four it gets, and the whole point of
2981    /// writing one is which. The four spellings are what gcc 16.2.0 writes for the same four
2982    /// programs, measured on x86-64 rather than read off a manual.
2983    ///
2984    /// The write hint is not one of them. `prefetchw` is not in the base instruction set and gcc
2985    /// writes it only when the command line says the part has it, so a prefetch for a write is the
2986    /// same instruction as a prefetch for a read, which is the fourth line here.
2987    #[test]
2988    fn a_prefetch_is_one_of_four_instructions_and_the_locality_is_what_picks() {
2989        for (locality, wanted) in
2990            [(0, "prefetchnta"), (1, "prefetcht2"), (2, "prefetcht1"), (3, "prefetcht0")]
2991        {
2992            let source =
2993                format!("void warm(void *p) {{ __builtin_prefetch(p, 0, {locality}); }}\n");
2994            let text = asm(&source);
2995            assert!(text.contains(&format!("\t{wanted}\t")), "locality {locality}: {text}");
2996        }
2997        // The one argument form, which means a read that wants all of the data afterwards.
2998        let text = asm("void warm(void *p) { __builtin_prefetch(p); }\n");
2999        assert!(text.contains("\tprefetcht0\t"), "{text}");
3000        // A prefetch for a write, which on a part nobody said has `prefetchw` is the same
3001        // instruction as the read above.
3002        let text = asm("void warm(void *p) { __builtin_prefetch(p, 1); }\n");
3003        assert!(text.contains("\tprefetcht0\t"), "{text}");
3004        assert!(!text.contains("prefetchw"), "{text}");
3005    }
3006
3007    /// The stop, which is the one instruction the machine is promised never to have a meaning for.
3008    ///
3009    /// What is checked is the instruction and not any effect, because the effect is a fault and a
3010    /// unit test has nowhere to take one. gcc 16.2.0 writes the same instruction for the same
3011    /// program, and it is not a call, which is the half that matters in a kernel and in a
3012    /// freestanding program: neither has an `abort` for a call to reach.
3013    ///
3014    /// The second half is the block going on after it. A statement written under a stop is
3015    /// compiled the way it would have been without one, so the addition is still there, and that
3016    /// is the front end declining to treat a stop as the end of a path.
3017    #[test]
3018    fn a_trap_is_the_instruction_the_machine_has_no_meaning_for() {
3019        let text = asm("void stop(void) { __builtin_trap(); }\n");
3020        assert!(text.contains("\tud2\n"), "{text}");
3021        assert!(!text.contains("\tcall"), "a stop is not a call to anything: {text}");
3022
3023        let text = asm("int stop(int a) { __builtin_trap(); return a + 1; }\n");
3024        assert!(text.contains("\tud2\n"), "{text}");
3025        assert!(text.contains("\taddl\t"), "the block goes on after a stop: {text}");
3026    }
3027
3028    /// The promise about the low bits of an address, whose value is the address.
3029    ///
3030    /// Nothing here reads an alignment fact about a value yet, so what the call leaves behind is
3031    /// its first argument and no instruction at all. The claim worth checking end to end is that
3032    /// the name is gone: a builtin nothing lowers reaches the assembler as a call to a name no
3033    /// object file defines, which is how this one used to fail to link out of glibc's string
3034    /// headers.
3035    ///
3036    /// The arguments behind the address are still evaluated, because gcc 16.2.0 evaluates them at
3037    /// every optimization level even though it has folded the call away. A constant has nothing to
3038    /// run and is dropped, and a call does, so the second half asks for the callee by name.
3039    #[test]
3040    fn assume_aligned_is_its_first_argument_and_keeps_the_rest() {
3041        let text = asm("void *aligned(char *p) { return __builtin_assume_aligned(p, 16); }\n");
3042        assert!(!text.contains("assume_aligned"), "{text}");
3043        assert!(!text.contains("\tcall"), "nothing is called for an alignment fact: {text}");
3044
3045        let source = "unsigned long width(void);\n\
3046                      void *aligned(char *p) { return __builtin_assume_aligned(p, width()); }\n";
3047        let text = asm(source);
3048        assert!(!text.contains("assume_aligned"), "{text}");
3049        assert!(text.contains("width"), "the argument that is not the answer still runs: {text}");
3050    }
3051
3052    /// Where a frame is, which on this machine is what the frame pointer holds.
3053    ///
3054    /// The first half is a function that would have kept no frame pointer at all, since it is a
3055    /// leaf with no locals, and keeps one because it asked where its frame is. The answer being
3056    /// `%rbp` rather than an offset off `%rsp` is the whole of the builtin at a depth of zero.
3057    ///
3058    /// The second half is the walk. Each link above zero is one load through the register the last
3059    /// one wrote, so a depth of two is two loads and a depth of three is three, which is what gcc
3060    /// 16.2.0 writes for the same programs at `-O2`.
3061    #[test]
3062    fn the_frame_address_is_the_frame_pointer_after_walking_that_many_links() {
3063        let text = asm("void *here(void) { return __builtin_frame_address(0); }\n");
3064        assert!(text.contains("pushq\t%rbp"), "a function that asks keeps a frame pointer: {text}");
3065        assert!(text.contains("movq\t%rbp, %rax"), "{text}");
3066        assert!(!text.contains("\tcall"), "a frame address is not a call to anything: {text}");
3067
3068        let walk = |depth: u32| {
3069            let source = format!("void *up(void) {{ return __builtin_frame_address({depth}); }}\n");
3070            asm(&source).matches("movq\t(%r").count()
3071        };
3072        assert_eq!(walk(1), 1, "one link is one load");
3073        assert_eq!(walk(3), 3, "three links are three loads");
3074    }
3075
3076    /// The address a frame returns to, which is one word above the frame the walk ended at.
3077    ///
3078    /// A word is eight bytes here and the `8(...)` is the whole claim: the call instruction pushed
3079    /// the return address and the prologue pushed the caller's frame pointer under it, so what the
3080    /// frame pointer points at is the link and what is above it is where control goes back to.
3081    /// gcc 16.2.0 writes `movq 8(%rbp), %rax` for the first of these, measured at `-O2`.
3082    ///
3083    /// The second half is the same walk the frame address does, with the load at the end of it
3084    /// reading one word further along rather than the register itself being the answer.
3085    #[test]
3086    fn the_return_address_is_one_word_above_the_frame_the_walk_ended_at() {
3087        let text = asm("void *back(void) { return __builtin_return_address(0); }\n");
3088        assert!(text.contains("pushq\t%rbp"), "a function that asks keeps a frame pointer: {text}");
3089        assert!(text.contains("movq\t8(%rbp), %rax"), "{text}");
3090        assert!(!text.contains("\tcall"), "a return address is not a call to anything: {text}");
3091
3092        let text = asm("void *back(void) { return __builtin_return_address(2); }\n");
3093        assert_eq!(text.matches("movq\t(%r").count(), 2, "two links are two loads: {text}");
3094        assert!(text.contains("movq\t8(%r"), "and the answer is above the last of them: {text}");
3095    }
3096
3097    /// A depth that is not a constant is refused, and so is one past the limit.
3098    ///
3099    /// The first is gcc's rule and not a convenience: what the call becomes is a walk that many
3100    /// links long, written out, so a number that is not known until the program runs has nothing
3101    /// to walk. gcc 16.2.0 says `invalid argument to '__builtin_return_address'` for the same
3102    /// program.
3103    ///
3104    /// The second is where this and gcc part company. gcc writes the walk however long it is, and
3105    /// this refuses a depth no program has a use for rather than filling an object file with loads
3106    /// that fault part way up.
3107    #[test]
3108    fn a_depth_that_is_not_a_small_constant_is_refused() {
3109        let mut opts = options();
3110        opts.emit = EmitKind::Ir;
3111        for source in [
3112            "void *up(int n) { return __builtin_return_address(n); }\n",
3113            "void *up(void) { return __builtin_frame_address(1000); }\n",
3114        ] {
3115            let messages = run(&opts, source).messages;
3116            let named = messages.iter().any(|m| m.contains("E0705"));
3117            assert!(named, "expected a refusal in {messages:?}");
3118        }
3119    }
3120
3121    /// Bytes off the frame, which is the stack pointer moving down and the answer being where it
3122    /// moved to.
3123    ///
3124    /// The rounding is the alignment: the size is taken up to the next sixteen before it is
3125    /// subtracted, so the pointer suits anything the program puts behind it. gcc 16.2.0 rounds the
3126    /// same way at `-O0` and spends a division doing it, which is the one place the two differ and
3127    /// is about how the rounding is written rather than about what it answers.
3128    ///
3129    /// There is no call anywhere in either program. An alloca that had reached the linker would
3130    /// have found the C library's, which is a real function with a real frame and is not what a
3131    /// program writing the builtin asked for.
3132    #[test]
3133    fn an_alloca_takes_the_bytes_off_the_stack_pointer_and_answers_where_they_are() {
3134        let text =
3135            asm("void use(void *p); void f(unsigned long n) { use(__builtin_alloca(n)); }\n");
3136        assert!(text.contains("andq\t$-16"), "the size is rounded up to sixteen: {text}");
3137        assert!(text.contains("subq\t%rdi, %rsp"), "and taken off the stack pointer: {text}");
3138        assert_eq!(text.matches("\tcall").count(), 1, "the only call is the one written: {text}");
3139
3140        // The plain name, which a program that declares it the way the C library does means the
3141        // same thing by. `gcc.c-torture/execute/20010122-1.c` is exactly this program.
3142        let plain = concat!(
3143            "extern void *alloca(__SIZE_TYPE__);\n",
3144            "void use(void *p);\n",
3145            "void f(unsigned long n) { use(alloca(n)); }\n",
3146        );
3147        let text = asm(plain);
3148        assert!(text.contains("subq\t%rdi, %rsp"), "the plain name is the same bytes: {text}");
3149        assert_eq!(text.matches("\tcall").count(), 1, "and is not a call either: {text}");
3150
3151        // And a program that means something of its own by the name keeps it, which is what the
3152        // declaration is looked at for.
3153        let own = concat!(
3154            "static void *alloca(unsigned long n) { return 0; }\n",
3155            "void *f(unsigned long n) { return alloca(n); }\n",
3156        );
3157        assert!(asm(own).contains("\tcall"), "a name the program took back is a call");
3158    }
3159
3160    /// The bytes an alloca took live until the function returns and not until the end of the block
3161    /// the call was written in.
3162    ///
3163    /// That is what makes it different from a variable length array, and the way it is kept is that
3164    /// every scope open where the call was written stops giving the stack back. The second program
3165    /// is the mixed case: an array in the outer block and an alloca in the inner one, where the
3166    /// inner block gives nothing back either even though an array is in scope that ordinarily
3167    /// would. gcc 16.2.0 at `-O0` writes no restore at the end of either block, measured rather
3168    /// than read off the manual.
3169    #[test]
3170    fn the_bytes_an_alloca_took_are_still_there_at_the_end_of_the_block_that_took_them() {
3171        let inner = "{ use(__builtin_alloca(n)); }";
3172        for body in [inner.to_owned(), format!("int a[n]; {inner} use(a);")] {
3173            let source = format!("void use(void *p);\nvoid f(unsigned long n) {{ {body} }}\n");
3174            let text = asm(&source);
3175            // Every instruction that writes the stack pointer, which in a function that gives
3176            // nothing back is the alloca taking bytes and the epilogue putting the frame pointer
3177            // there. A restore would be a third kind, a move out of a register the save wrote.
3178            for line in text.lines().filter(|line| line.trim_end().ends_with(", %rsp")) {
3179                let taking = line.contains("subq");
3180                let leaving = line.contains("%rbp");
3181                assert!(taking || leaving, "nothing puts the stack back: {line} in {text}");
3182            }
3183        }
3184    }
3185
3186    /// Not a rewording of the check above: what the two paths agree about is the point.
3187    #[test]
3188    fn the_object_and_the_listing_are_two_spellings_of_one_compilation() {
3189        // A call, because it is the one thing whose spelling in the two differs completely: the
3190        // listing writes a name and the object writes four zero bytes and a relocation asking the
3191        // linker for the same name. If either path had lost the callee, one of these would fail.
3192        let source = "int callee(void); int g(void) { return callee(); }\n";
3193        let bytes = obj(source);
3194        assert!(
3195            bytes.windows(7).any(|w| w == b"callee\0"),
3196            "the object has to name the callee for the linker to find it"
3197        );
3198        let text = asm(source);
3199        assert!(text.contains("\tcall\tcallee\n"), "{text}");
3200    }
3201
3202    /// What a file of a link contributes is an object, and the default emit is a link.
3203    ///
3204    /// This is here because getting it wrong is silent in the worst way: an empty file is a valid
3205    /// empty linker script, so a link fed one gets as far as reporting every symbol of the file as
3206    /// undefined and says nothing about the compilation that produced nothing.
3207    #[test]
3208    fn compiling_for_an_executable_produces_an_object_and_not_a_dump() {
3209        let mut opts = options();
3210        // What a command line with no `-c` and no `-S` on it asks for.
3211        opts.emit = EmitKind::Executable;
3212        let result = run(&opts, "int main(void) { return 0; }\n");
3213        assert_eq!(result.messages, Vec::<String>::new());
3214        match result.artifact {
3215            Artifact::Object { bytes, .. } => assert_eq!(&bytes[..4], b"\x7fELF"),
3216            other => panic!("expected an object, got {other:?}"),
3217        }
3218    }
3219
3220    /// A target with a back end but no object writer says so rather than writing the wrong file.
3221    #[test]
3222    fn a_platform_with_no_object_writer_is_said_so_rather_than_written_as_elf() {
3223        let mut opts = options();
3224        opts.emit = EmitKind::Object;
3225        opts.target = "x86_64-apple-darwin".parse::<Triple>().unwrap();
3226        let result = run(&opts, "int f(void) { return 0; }\n");
3227        assert!(result.failed(), "an object nobody can read is worse than a message");
3228        assert!(
3229            result.messages.iter().any(|m| m.contains("no object writer")),
3230            "{:?}",
3231            result.messages
3232        );
3233    }
3234
3235    /// The IR of `source`, insisting that it compiled cleanly.
3236    fn ir(source: &str) -> String {
3237        let mut opts = options();
3238        opts.emit = EmitKind::Ir;
3239        let result = run(&opts, source);
3240        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3241        result.text().to_owned()
3242    }
3243
3244    /// What was said about `source`, insisting that something was.
3245    fn errors(source: &str) -> Vec<String> {
3246        let mut opts = options();
3247        opts.emit = EmitKind::Ir;
3248        let result = run(&opts, source);
3249        assert!(result.failed(), "expected this to be refused:\n{source}");
3250        result.messages
3251    }
3252
3253    /// The body of the one function in `source`, which is what most of these are about.
3254    fn body(source: &str) -> String {
3255        let text = ir(source);
3256        let (_, rest) = text.split_once("{\n").expect("a function definition");
3257        let (body, _) = rest.rsplit_once("}\n").expect("a function definition");
3258        body.to_owned()
3259    }
3260
3261    /// What `-fgnu89-inline` is for, seen at the only place it shows: whether a body reached the
3262    /// module or only a declaration did.
3263    ///
3264    /// The C99 reading is the one an inline definition is written for and is not being changed
3265    /// here. What the flag is for is a program written before C99 swapped the two, which relies on
3266    /// `inline` alone leaving something behind for another unit to call, and there are twelve of
3267    /// those in the GCC torture suite alone.
3268    #[test]
3269    fn gnu89_inline_is_what_decides_whether_a_bare_inline_definition_reaches_the_module() {
3270        let source = "inline int f(int x) { return x + 1; }\n";
3271        let with = |flag: bool| {
3272            let mut opts = options();
3273            opts.emit = EmitKind::Ir;
3274            opts.gnu89_inline = flag;
3275            let result = run(&opts, source);
3276            assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile");
3277            result.text().to_owned()
3278        };
3279
3280        // Under C's reading the module holds the declaration and the calls in this unit go to
3281        // whatever definition another unit has, which is C 6.7.4p7 and is what gcc does too.
3282        assert!(!with(false).contains("block0"), "no body: {}", with(false));
3283
3284        // Under GNU's it is an ordinary external definition, so the body is there and the symbol
3285        // is one the linker can resolve against.
3286        assert!(with(true).contains("block0"), "a body: {}", with(true));
3287    }
3288
3289    /// Every shape that reads or writes through a C type names that type.
3290    ///
3291    /// The tree itself is `rucc_lower::aliasing`'s and is tested there. What this is about is that
3292    /// the walk reaches it from every shape a program actually writes, since a node on the scalar
3293    /// load and nothing on the member load would be a layer that answers for a third of the
3294    /// accesses in a program and is not worth having.
3295    #[test]
3296    fn an_access_through_a_type_names_the_type_it_went_through() {
3297        let source = "\
3298struct s { int a; float b; };\n\
3299union u { int i; float f; };\n\
3300int scalar(int *p) { return *p; }\n\
3301float member(struct s *p) { p->a = 1; return p->b; }\n\
3302int element(int *a, long i) { return a[i]; }\n\
3303float through_a_union(union u *p) { p->i = 1; return p->f; }\n";
3304        let text = ir(source);
3305        assert!(text.contains(r#"!0 = tbaa "char""#), "the root: {text}");
3306        assert!(text.contains(r#"tbaa "int", parent !0"#), "int under it: {text}");
3307        assert!(text.contains(r#"tbaa "float", parent !0"#), "float under it: {text}");
3308        // One per access, and a function whose accesses all go through one type says so once per
3309        // access rather than once per function.
3310        let named = text.lines().filter(|line| line.contains(", tbaa !")).count();
3311        assert_eq!(named, 6, "six accesses: {text}");
3312    }
3313
3314    /// `-fno-strict-aliasing` is the front end leaving the name off.
3315    ///
3316    /// Nothing asks the alias analysis anything yet, so no program compiles differently for having
3317    /// passed this today. What this test is for is the day one does: the flag has to be the
3318    /// absence of the names rather than a condition somewhere downstream, since that is the only
3319    /// version of it that a pass added later cannot forget about.
3320    #[test]
3321    fn turning_strict_aliasing_off_leaves_the_type_off_every_access() {
3322        let source = "int punned(float *f, int *i) { *i = 1; *f = 2.0f; return *i; }\n";
3323        let mut opts = options();
3324        opts.emit = EmitKind::Ir;
3325        opts.strict_aliasing = false;
3326        let result = run(&opts, source);
3327        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile");
3328        let text = result.text().to_owned();
3329        assert!(!text.contains("tbaa"), "not even the root: {text}");
3330    }
3331
3332    /// `return;` from a function that promised a value, which only C89 lets through and which
3333    /// therefore only reaches the IR builder under that dialect.
3334    ///
3335    /// Zero goes back. The alternatives are worse: an empty return list builds a `ret` the
3336    /// verifier refuses, which is what a torture case found, and `unreachable` would be a claim
3337    /// that the branch reaching this never runs, which is a claim about the program rather than
3338    /// about the value and lets the optimizer delete the path that led here.
3339    #[test]
3340    fn a_bare_return_from_a_function_that_promised_a_value_gives_back_a_zero() {
3341        let mut opts = options();
3342        opts.emit = EmitKind::Ir;
3343        opts.std = Std::C89;
3344        let compiled = |source: &str| {
3345            let result = run(&opts, source);
3346            assert_eq!(result.messages, Vec::<String>::new(), "C89 has nothing to say about this");
3347            result.text().to_owned()
3348        };
3349
3350        let text = compiled("int f(int x) { if (x) return; return 3; }\n");
3351        assert!(text.contains("iconst.i32 0\n    return"), "zero goes back: {text}");
3352        assert!(!text.contains("unreachable"), "the branch that reached it is kept: {text}");
3353
3354        // A floating point return needs the constant of its own kind rather than an integer one.
3355        let text = compiled("double f(int x) { if (x) return; return 1.0; }\n");
3356        assert!(text.contains("fconst.f64 0x0\n    return"), "a float zero goes back: {text}");
3357    }
3358
3359    /// What C89 6.3.2.2 declares for a call to a name nothing declared, seen in the IR rather than
3360    /// in what was said about it.
3361    ///
3362    /// `extern int f();`, so the call gives back an `int` and its arguments are promoted rather
3363    /// than converted to parameters there are none of. The declaration lasts for the file, which
3364    /// is what makes a second call to the same name ordinary and is why gcc says this once per
3365    /// file rather than once per call.
3366    #[test]
3367    fn a_call_to_a_name_nothing_declared_declares_it_as_c89_said_to() {
3368        let mut opts = options();
3369        opts.emit = EmitKind::Ir;
3370        opts.std = Std::C89;
3371        let compiled = |source: &str| {
3372            let result = run(&opts, source);
3373            assert_eq!(result.messages, Vec::<String>::new(), "C89 has nothing to say about this");
3374            result.text().to_owned()
3375        };
3376
3377        // An `int` back, which is the whole of what the implicit declaration says.
3378        let text = compiled("int f(void) { return g(); }\n");
3379        assert!(text.contains("call @g"), "the call is to the name that was written: {text}");
3380        assert!(text.contains("i32"), "and it gives back an int: {text}");
3381
3382        // No prototype, so a `char` argument arrives promoted to `int` the way an argument to a
3383        // function whose parameters are unspecified does.
3384        let text = compiled("int f(char c) { return g(c); }\n");
3385        assert!(text.contains("sext.i32"), "the argument is promoted: {text}");
3386
3387        // A name written as a value rather than called is still undeclared, since the rule is
3388        // about a call and nothing else.
3389        let mut opts = options();
3390        opts.std = Std::C89;
3391        let said = run(&opts, "int f(void) { return h; }\n").messages.join("\n");
3392        assert!(said.contains("'h' undeclared"), "not a call, so not declared: {said}");
3393    }
3394
3395    /// A file that calls a name above the definition of it, which is the shape the implicit
3396    /// declaration has to survive rather than swallow.
3397    ///
3398    /// The definition merges into the declaration the call already made rather than making a
3399    /// second one, so a declaration the tree does not carry at the top level takes the definition
3400    /// down with it: the body is attached to a node nothing walks and no function comes out.
3401    /// Nothing about the call itself looks wrong when that happens, and the program gets to the
3402    /// linker before anyone finds out, which is where `execute/cmpsi-1.c` in the torture suite
3403    /// found it, as an undefined reference to a name defined eleven lines further down.
3404    #[test]
3405    fn a_name_called_before_it_is_defined_still_gets_its_definition() {
3406        let mut opts = options();
3407        opts.emit = EmitKind::Ir;
3408        opts.std = Std::C89;
3409        let text = run(&opts, "int f(void) { return dummy(); }\ndummy () { return 7; }\n")
3410            .text()
3411            .to_owned();
3412        assert!(text.contains("func @f()"), "the caller is there: {text}");
3413        assert!(text.contains("func @dummy"), "and so is what it calls: {text}");
3414        assert!(text.contains("iconst.i32 7"), "with the body it was given: {text}");
3415    }
3416
3417    /// An old style definition whose parameter is narrower than what a call passes it.
3418    ///
3419    /// There is no prototype for a call to convert its argument to, so the argument is promoted
3420    /// and an `int` arrives for a parameter the body reads as an `unsigned char`. The entry block
3421    /// is where the two meet, and gcc writes the same pair of instructions there: store the low
3422    /// byte, read it back widened. `execute/950605-1.c` in the torture suite calls `f(-1)` and
3423    /// checks the parameter against `0xFF`, which is the difference between converting and not.
3424    #[test]
3425    fn an_old_style_parameter_is_converted_from_what_the_call_promoted_it_to() {
3426        let mut opts = options();
3427        opts.emit = EmitKind::Ir;
3428        opts.std = Std::C89;
3429        let compiled = |source: &str| run(&opts, source).text().to_owned();
3430
3431        let text = compiled("f (c) unsigned char c; { return c; }\n");
3432        assert!(text.contains("func @f(i32"), "an int arrives: {text}");
3433        assert!(text.contains("trunc.i8"), "and is cut down to what was declared: {text}");
3434        assert!(text.contains("zext.i32"), "then read back unsigned: {text}");
3435
3436        // A `short` is the same shape and signed, so it comes back the other way.
3437        let text = compiled("f (s) short s; { return s; }\n");
3438        assert!(text.contains("trunc.i16"), "cut down: {text}");
3439        assert!(text.contains("sext.i32"), "and read back signed: {text}");
3440
3441        // A `float` parameter is promoted to `double`, and without the conversion the multiply
3442        // below has one f64 operand and one f32, which the verifier refuses as invalid IR.
3443        let text = compiled("f (x) float x; { return x * 2; }\n");
3444        assert!(text.contains("func @f(f64"), "a double arrives: {text}");
3445        assert!(text.contains("fptrunc.f32"), "and is narrowed to the float: {text}");
3446
3447        // A parameter a prototype named arrives as itself and nothing is converted, which is the
3448        // case this must not have changed.
3449        let text = compiled("int f(unsigned char c) { return c; }\n");
3450        assert!(text.contains("func @f(i8)"), "the declared type arrives: {text}");
3451        assert!(!text.contains("trunc"), "so there is nothing to cut down: {text}");
3452    }
3453
3454    /// The six rules gcc 14 turned from a warning into an error, and the three answers each one
3455    /// gets depending on the dialect and on `-fpermissive`.
3456    ///
3457    /// The table is a measurement rather than a reading of the release notes. Six files, one per
3458    /// rule, put through gcc 16.2.0 on x86-64 Linux under each of the four command lines below
3459    /// with no `-W` flags on any of them, and what came back is what is written here. The three
3460    /// rules that say nothing under C89 are the three C89 did not have, and the three that warn
3461    /// there were constraint violations then as well.
3462    #[test]
3463    fn the_rules_gcc_promoted_are_decided_by_the_dialect_and_by_fpermissive() {
3464        // `-std=gnu89`, `-std=gnu17`, `-std=gnu17 -fpermissive`, and `-std=gnu23`.
3465        let modes = [(Std::C89, false), (Std::C17, false), (Std::C17, true), (Std::C23, false)];
3466        let cases = [
3467            ("static counted;\n", ["", "error", "warning", "error"]),
3468            ("int f(void) { return g(); }\n", ["", "error", "warning", "error"]),
3469            ("int f(x) { return x; }\n", ["", "error", "warning", "error"]),
3470            ("int *p;\nvoid h(void) { p = 1; }\n", ["warning", "error", "warning", "error"]),
3471            (
3472                "char *q;\nint *r;\nvoid k(void) { r = q; }\n",
3473                ["warning", "error", "warning", "error"],
3474            ),
3475            ("int f(void) { return; }\n", ["", "error", "warning", "error"]),
3476            ("void g(void) { return 1; }\n", ["warning", "error", "warning", "error"]),
3477        ];
3478
3479        for (source, wanted) in cases {
3480            for (&(std, permissive), wanted) in modes.iter().zip(wanted) {
3481                let mut opts = options();
3482                opts.std = std;
3483                opts.permissive = permissive;
3484                let said = run(&opts, source).messages.join("\n");
3485                let severity = if said.contains(": error: ") {
3486                    "error"
3487                } else if said.contains(": warning: ") {
3488                    "warning"
3489                } else {
3490                    ""
3491                };
3492                let how = if permissive { " -fpermissive" } else { "" };
3493                assert_eq!(
3494                    severity,
3495                    wanted,
3496                    "under -std={}{how}, {source} was answered with `{said}`",
3497                    std.as_str()
3498                );
3499                if wanted.is_empty() {
3500                    assert!(said.is_empty(), "nothing to say, but said `{said}`");
3501                }
3502            }
3503        }
3504    }
3505
3506    /// A first argument that is not a list, which the four variadic operators answer in two ways.
3507    ///
3508    /// gcc has `va_arg` as an operator, since it takes a type name and no function can, and the
3509    /// other three as builtin functions taking the address of a list. The difference is not a
3510    /// naming one: the operator's complaint is its own and is an error under every dialect, and
3511    /// the three functions go through the ordinary rule about an argument of the wrong type,
3512    /// which is one of the rules the table above is about. The same four command lines through
3513    /// gcc 16.2.0 on x86-64 Linux is where these came from.
3514    #[test]
3515    fn the_three_variadic_builtins_answer_a_bad_list_the_way_a_call_answers_a_bad_argument() {
3516        let modes = [(Std::C89, false), (Std::C17, false), (Std::C17, true), (Std::C23, false)];
3517        let cases = [
3518            (
3519                "int f(int n, ...) { char *p; return __builtin_va_arg(p, int); }\n",
3520                "first argument to 'va_arg' not of type 'va_list'",
3521                ["error", "error", "error", "error"],
3522            ),
3523            (
3524                "void f(int n, ...) { char *p; __builtin_va_start(p, n); }\n",
3525                "passing argument 1 of '__builtin_va_start' from incompatible pointer type",
3526                ["warning", "error", "warning", "error"],
3527            ),
3528            (
3529                "void f(int n, ...) { int x; __builtin_va_end(x); }\n",
3530                "passing argument 1 of '__builtin_va_end' makes pointer from integer without a \
3531                 cast",
3532                ["warning", "error", "warning", "error"],
3533            ),
3534            (
3535                "void f(int n, ...) { __builtin_va_list a; char *p; __builtin_va_copy(a, p); }\n",
3536                "passing argument 2 of '__builtin_va_copy' from incompatible pointer type",
3537                ["warning", "error", "warning", "error"],
3538            ),
3539        ];
3540
3541        for (source, message, wanted) in cases {
3542            for (&(std, permissive), wanted) in modes.iter().zip(wanted) {
3543                let mut opts = options();
3544                opts.std = std;
3545                opts.permissive = permissive;
3546                let said = run(&opts, source).messages.join("\n");
3547                let how = if permissive { " -fpermissive" } else { "" };
3548                assert!(
3549                    said.contains(&format!(": {wanted}: {message}")),
3550                    "under -std={}{how}, {source} was answered with `{said}`",
3551                    std.as_str()
3552                );
3553            }
3554        }
3555    }
3556
3557    /// The IR of `source` at one safety tier, insisting that it compiled cleanly.
3558    fn safe_ir(tier: rucc_session::Safety, source: &str) -> String {
3559        let mut opts = options();
3560        opts.emit = EmitKind::Ir;
3561        opts.safety = tier;
3562        let result = run(&opts, source);
3563        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3564        result.text().to_owned()
3565    }
3566
3567    const READS_THROUGH_A_POINTER: &str = "int read(int *p) { return p[1]; }\n";
3568
3569    /// The IR for a source built with a tier and a padding mode.
3570    fn padded_ir(padding: Padding, source: &str) -> String {
3571        let mut opts = options();
3572        opts.emit = EmitKind::Ir;
3573        opts.safety = rucc_session::Safety::Detect;
3574        opts.padding = padding;
3575        let result = run(&opts, source);
3576        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3577        result.text().to_owned()
3578    }
3579
3580    const FILLS_A_RECORD_A_MEMBER_AT_A_TIME: &str = "struct padded { char tag; int value; };\n\
3581         void fill(struct padded *p) { p->tag = 1; p->value = 2; }\n";
3582
3583    #[test]
3584    fn a_record_filled_a_member_at_a_time_comes_out_whole_when_padding_does_not_participate() {
3585        // Section 9.3 of document 09, and the reason the default is the one it gives library code.
3586        // Four bytes from the `char` and four from the `int` is the whole of an eight byte record,
3587        // so the `memcmp` or the hash or the `write` that reads it back is not refused.
3588        let text = padded_ir(Padding::Ignored, FILLS_A_RECORD_A_MEMBER_AT_A_TIME);
3589        assert_eq!(text.matches("owns 4").count(), 2, "{text}");
3590    }
3591
3592    #[test]
3593    fn a_store_says_only_what_it_wrote_when_padding_does_participate() {
3594        // The kernel profile's default, which is section 9.3's actual rule: the padding stays
3595        // unwritten and the read of the record that would leak it is the one that reports.
3596        let text = padded_ir(Padding::Tracked, FILLS_A_RECORD_A_MEMBER_AT_A_TIME);
3597        assert!(!text.contains("owns"), "{text}");
3598    }
3599
3600    #[test]
3601    fn a_member_of_a_union_owns_nothing_after_it() {
3602        // The bytes after a short member of a union belong to a longer member rather than to
3603        // padding, and saying a store through the short one wrote them would be saying the longer
3604        // one holds a value nobody put there.
3605        let text = padded_ir(
3606            Padding::Ignored,
3607            "union u { char tag; long wide; };\nvoid fill(union u *p) { p->tag = 1; }\n",
3608        );
3609        assert!(!text.contains("owns"), "{text}");
3610    }
3611
3612    #[test]
3613    fn an_inner_records_trailing_padding_reaches_the_outer_records() {
3614        // The composition. `in` owns four bytes of `outer` because `x` starts there, and `c` is
3615        // the last member of `in`, so what it owns is what `in` owns rather than its own one byte.
3616        // Without that the three bytes between them would stay unwritten and a read of the whole
3617        // thing would report.
3618        let text = padded_ir(
3619            Padding::Ignored,
3620            "struct inner { char c; };\n\
3621             struct outer { struct inner in; int x; };\n\
3622             void fill(struct outer *p) { p->in.c = 1; p->x = 2; }\n",
3623        );
3624        assert_eq!(text.matches("owns 4").count(), 2, "{text}");
3625    }
3626
3627    #[test]
3628    fn a_build_that_did_not_ask_for_the_monitor_is_compiled_the_way_it_always_was() {
3629        // This is the load bearing test of the whole flag. The monitor is being built in the open
3630        // and every build in the world is compiled by this compiler with the flag absent, so a
3631        // check that leaked into that path would be a regression for everybody.
3632        let text = ir(READS_THROUGH_A_POINTER);
3633        assert!(!text.contains("check_"), "{text}");
3634        assert!(!text.contains("cap_of"), "{text}");
3635    }
3636
3637    #[test]
3638    fn asking_for_a_tier_puts_the_checks_in_before_the_optimizer_sees_them() {
3639        let text = safe_ir(rucc_session::Safety::Detect, READS_THROUGH_A_POINTER);
3640        assert!(text.contains("cap_of"), "{text}");
3641        assert!(text.contains("check_bounds"), "{text}");
3642        assert!(text.contains("check_live"), "{text}");
3643        // The subscript is address arithmetic, so J2 applies to it as well as J1.
3644        assert!(text.contains("check_deriv"), "{text}");
3645        // And the read names a type, so it asks the type plane about the bytes as well.
3646        assert!(text.contains("check_type"), "{text}");
3647    }
3648
3649    #[test]
3650    fn the_three_tiers_that_are_not_off_all_check_the_same_accesses_so_far() {
3651        // What separates them is the reporter and the boundary, which are milestones S2 and S3.
3652        // Pinning it here means the day they stop agreeing, this test says so rather than the
3653        // difference going unnoticed.
3654        let detect = safe_ir(rucc_session::Safety::Detect, READS_THROUGH_A_POINTER);
3655        for tier in [rucc_session::Safety::Enforce, rucc_session::Safety::Kernel] {
3656            assert_eq!(safe_ir(tier, READS_THROUGH_A_POINTER), detect, "{tier}");
3657        }
3658    }
3659
3660    /// The safety summary of `source` at one tier, insisting that it compiled cleanly.
3661    fn summary(tier: rucc_session::Safety, source: &str) -> String {
3662        let mut opts = options();
3663        opts.emit = EmitKind::SafetySummary;
3664        opts.safety = tier;
3665        let result = run(&opts, source);
3666        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3667        result.text().to_owned()
3668    }
3669
3670    #[test]
3671    fn the_summary_counts_the_checks_that_went_in_and_the_ones_still_standing() {
3672        let text = summary(rucc_session::Safety::Detect, READS_THROUGH_A_POINTER);
3673        assert!(text.contains("\"tier\": \"detect\""), "{text}");
3674        // One load, so one of each of the two access checks, and the subscript is a derivation.
3675        assert!(
3676            text.contains("\"bounds\": { \"emitted\": 1, \"remaining\": 1, \"discharged\": 0 }"),
3677            "{text}"
3678        );
3679        assert!(
3680            text.contains(
3681                "\"derivation\": { \"emitted\": 1, \"remaining\": 1, \"discharged\": 0 }"
3682            ),
3683            "{text}"
3684        );
3685    }
3686
3687    #[test]
3688    fn a_build_without_the_monitor_summarises_as_a_build_with_no_checks_in_it() {
3689        // Which is the honest summary rather than an error. A build system that emits a summary
3690        // for every unit should get one for the units nobody asked to instrument too, and the
3691        // zeroes are what say that the guarantee over that file is nothing at all.
3692        let text = summary(rucc_session::Safety::Off, READS_THROUGH_A_POINTER);
3693        assert!(text.contains("\"tier\": \"off\""), "{text}");
3694        assert!(
3695            text.contains("\"bounds\": { \"emitted\": 0, \"remaining\": 0, \"discharged\": 0 }"),
3696            "{text}"
3697        );
3698    }
3699
3700    #[test]
3701    fn a_call_the_boundary_models_is_counted_apart_from_one_it_does_not() {
3702        let text = summary(
3703            rucc_session::Safety::Detect,
3704            "void *memcpy(void *, const void *, unsigned long);\n\
3705             int puts(const char *);\n\
3706             void f(char *d, char *s) { memcpy(d, s, 4); puts(d); }\n",
3707        );
3708        assert!(text.contains("\"interposed\": 1"), "{text}");
3709        assert!(text.contains("\"puts\""), "{text}");
3710        // The wrapper it was pointed at is ours, so it is not on the list of things this build
3711        // failed to model. Counting it there would make instrumenting a file look worse than
3712        // leaving it alone.
3713        assert!(!text.contains("__rucc_wrap_memcpy\""), "{text}");
3714    }
3715
3716    #[test]
3717    fn the_two_directions_a_pointer_crosses_the_boundary_are_counted_apart() {
3718        // `f` is a name the linker can bind to and takes a pointer, so a pointer arrives there.
3719        // `notes_open` is a library this build did not instrument, so a pointer comes back from
3720        // it. Both are crossings and neither is the other, which is why there are two numbers.
3721        let text = summary(
3722            rucc_session::Safety::Detect,
3723            "void *notes_open(void);\n\
3724             char *f(char *p) { char *q = notes_open(); return q ? q : p; }\n",
3725        );
3726        assert!(text.contains("\"crossings\": { \"entered\": 1, \"returned\": 1 }"), "{text}");
3727        assert!(text.contains("\"notes_open\""), "{text}");
3728    }
3729
3730    #[test]
3731    fn a_static_function_nobody_takes_the_address_of_is_not_a_crossing() {
3732        // Nothing outside the file can reach it, so a witness on its parameters would be counting
3733        // a crossing that does not happen.
3734        let text = summary(
3735            rucc_session::Safety::Detect,
3736            "static int len(const char *p) { return p ? 1 : 0; }\n\
3737             int f(void) { return len(\"x\"); }\n",
3738        );
3739        assert!(text.contains("\"crossings\": { \"entered\": 0, \"returned\": 0 }"), "{text}");
3740    }
3741
3742    /// The granule report for `source`, insisting that it compiled cleanly.
3743    fn granules(source: &str) -> String {
3744        let mut opts = options();
3745        opts.emit = EmitKind::TypeGranules;
3746        let result = run(&opts, source);
3747        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3748        result.text().to_owned()
3749    }
3750
3751    #[test]
3752    fn the_granule_report_names_every_record_and_both_keyings() {
3753        let text = granules(
3754            "struct hot { char *p; int a; int b; };\n\
3755             int f(struct hot *h) { return h->a; }\n",
3756        );
3757        assert!(text.contains("struct hot"), "{text}");
3758        // Both keyings are reported because which types count as one is a decision the design
3759        // has not made yet, and a report that picked one would be hiding the cost of the other.
3760        assert!(text.contains("every type distinct"), "{text}");
3761        assert!(text.contains("every pointer one type"), "{text}");
3762        assert!(text.contains("budget"), "{text}");
3763    }
3764
3765    #[test]
3766    fn a_record_nothing_uses_is_still_measured() {
3767        // The measurement is about what a program declares, not about what it runs, so a type
3768        // that is only ever declared still costs the plane whatever its layout costs.
3769        let text = granules("struct unused { long a; double b; };\nint f(void) { return 0; }\n");
3770        assert!(text.contains("struct unused"), "{text}");
3771    }
3772
3773    #[test]
3774    fn the_granule_report_stops_before_anything_is_lowered() {
3775        // A layout is settled at the closing brace, so lowering the function bodies would take
3776        // minutes on an amalgamation and answer nothing. The evidence that it stops is that a
3777        // body the back end has no way to compile still produces a report.
3778        let text = granules(
3779            "struct wide { long double d; };\n\
3780             long double f(long double x) { return x * x; }\n",
3781        );
3782        assert!(text.contains("struct wide"), "{text}");
3783    }
3784
3785    #[test]
3786    fn a_witness_reaches_the_assembler_as_a_call_to_the_runtime() {
3787        // The count only means anything if the call is really there, and a summary saying one is
3788        // there is not evidence that the back end emitted it.
3789        let text = safe_asm(rucc_session::Safety::Detect, "char *f(char *p) { return p; }\n");
3790        assert!(text.contains("\tcall\t__rucc_cap_witness\n"), "{text}");
3791    }
3792
3793    #[test]
3794    fn a_pointer_turned_into_an_integer_is_on_the_trust_set() {
3795        let text = summary(
3796            rucc_session::Safety::Detect,
3797            "unsigned long f(int *p) { return (unsigned long) p; }\n",
3798        );
3799        assert!(text.contains("\"exposed\": 1"), "{text}");
3800    }
3801
3802    /// The assembly of `source` at one safety tier, insisting that it compiled cleanly.
3803    fn safe_asm(tier: rucc_session::Safety, source: &str) -> String {
3804        let mut opts = options();
3805        opts.emit = EmitKind::Asm;
3806        opts.safety = tier;
3807        let result = run(&opts, source);
3808        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
3809        result.text().to_owned()
3810    }
3811
3812    #[test]
3813    fn a_check_reaches_the_assembler_as_a_call_to_the_runtime() {
3814        let text = safe_asm(rucc_session::Safety::Detect, READS_THROUGH_A_POINTER);
3815        assert!(text.contains("\tcall\t__rucc_check_bounds\n"), "{text}");
3816        assert!(text.contains("\tcall\t__rucc_check_live\n"), "{text}");
3817        assert!(text.contains("\tcall\t__rucc_check_deriv\n"), "{text}");
3818        assert!(text.contains("\tcall\t__rucc_check_type\n"), "{text}");
3819        assert!(text.contains("\tcall\t__rucc_check_init\n"), "{text}");
3820    }
3821
3822    #[test]
3823    fn every_check_that_reached_the_assembler_has_a_row_describing_it() {
3824        // Five checks and five descriptors, each in the section the runtime's reporter reads.
3825        // The width is `rucc_safety::lower::WIDTH` and the row is `rucc_safe_rt::fail::Descriptor`,
3826        // and the two agreeing is what makes the address a check is handed mean anything.
3827        let text = safe_asm(rucc_session::Safety::Detect, READS_THROUGH_A_POINTER);
3828        let section = format!("\t.section\t{},", rucc_safety::SECTION);
3829        assert_eq!(text.matches(&section).count(), 5, "{text}");
3830        for index in 0..5 {
3831            let name = format!("__rucc_safety_desc_{index}");
3832            // Defined once and referenced once, because a descriptor nothing points at describes
3833            // nothing and a reference with no definition does not link.
3834            assert!(text.contains(&format!("{name}:\n")), "{text}");
3835            assert!(text.contains(&format!("{name}(%rip)")), "{text}");
3836        }
3837        assert!(!text.contains("__rucc_safety_desc_5"), "{text}");
3838    }
3839
3840    /// `__builtin_constant_p` is answered in the front end and never reaches the IR.
3841    ///
3842    /// gcc folds it after optimization, so its answer for an argument that is not written as a
3843    /// constant can differ between `-O0` and `-O2`. What is checked here is the front end's
3844    /// answer, which is the same at every level, and the four cases where gcc gives the same
3845    /// answer at both levels are the ones measured on gcc 16: a literal is one, a variable is
3846    /// zero, a string literal is one and the address of an object is zero.
3847    #[test]
3848    fn builtin_constant_p_is_folded_where_it_is_written_rather_than_called() {
3849        let text = ir(concat!(
3850            "int g;\n",
3851            "int a = __builtin_constant_p(1);\n",
3852            "int b = __builtin_constant_p(g);\n",
3853            "int c = __builtin_constant_p(\"abc\");\n",
3854            "int d = __builtin_constant_p(&g);\n",
3855            "int e = __builtin_constant_p(1.5);\n",
3856            "int h = __builtin_choose_expr(__builtin_constant_p(3), 11, 22);\n",
3857        ));
3858        assert!(text.contains("global @a : i32 = 1,"), "{text}");
3859        assert!(text.contains("global @b : i32 = 0,"), "{text}");
3860        assert!(text.contains("global @c : i32 = 1,"), "{text}");
3861        assert!(text.contains("global @d : i32 = 0,"), "{text}");
3862        assert!(text.contains("global @e : i32 = 1,"), "{text}");
3863        assert!(text.contains("global @h : i32 = 11,"), "{text}");
3864        assert!(!text.contains("__builtin_constant_p"), "it is not a call to anything:\n{text}");
3865
3866        // The argument is not evaluated, which is what gcc does with it as well, so `i` is
3867        // still zero. The second constant is the answer, which nothing reads and which the
3868        // first pass that looks for dead code will take out.
3869        let text = body("int f(void) { int i = 0; __builtin_constant_p(i++); return i; }\n");
3870        assert_eq!(text, "block0:\n    %0 = iconst.i32 0\n    %1 = iconst.i32 0\n    return %0\n");
3871    }
3872
3873    /// A library builtin is the library function of the same name, and the call says so.
3874    ///
3875    /// A program writes `__builtin_strlen` rather than `strlen` to reach the function the C
3876    /// library promises where its own name has been taken by a macro, and to say that the usual
3877    /// meaning is the one intended. So the name in the program and the name in the object file
3878    /// are two different names and the call carries the second one. gcc folds several of these
3879    /// when the arguments allow it, which is an optimization on top of a call that is already
3880    /// right rather than instead of it, so nothing here depends on any folding happening.
3881    #[test]
3882    fn a_call_to_a_library_builtin_reaches_the_library_function() {
3883        let text = body("void f(void) { __builtin_abort(); }\n");
3884        assert_eq!(text, "block0:\n    call @abort() : ()\n    return\n");
3885
3886        // Nothing declared either of these and nothing had to: the prefix is what says the name
3887        // belongs to the implementation, and the type comes out of `features.toml`.
3888        let text = ir("int f(const char *s) { return __builtin_puts(s) + __builtin_strlen(s); }\n");
3889        assert!(text.contains("call @puts(%0) : (ptr) -> i32"), "{text}");
3890        assert!(text.contains("call @strlen(%0) : (ptr) -> i64"), "{text}");
3891        assert!(!text.contains("__builtin_"), "the prefix is not part of any name here:\n{text}");
3892    }
3893
3894    /// A `_chk` builtin reaches the checking function in the library with the object size still
3895    /// on the end of it.
3896    ///
3897    /// This is what a fortified `string.h` turns every copy into, so it is what a program built
3898    /// the way a distribution builds one is full of, and the whole of what makes the call right
3899    /// is that the size goes with it. The checking function takes `(size_t) -1` to mean nothing
3900    /// is known and does no check, which is what the header passes when the destination's object
3901    /// is not in sight, so the unconditional call means the same thing in both cases and costs a
3902    /// call gcc would have folded away in the second.
3903    ///
3904    /// The name is the one place this family reads like an exception and is not one:
3905    /// `__builtin___memcpy_chk` with `__builtin_` taken off is `__memcpy_chk`.
3906    #[test]
3907    fn a_chk_builtin_reaches_the_checking_function_and_keeps_the_size() {
3908        let text = ir(concat!(
3909            "char d[8];\n",
3910            "void f(const char *s, unsigned long n) {\n",
3911            "  __builtin___memcpy_chk(d, s, n, __builtin_object_size(d, 0));\n",
3912            "  __builtin___strcpy_chk(d, s, __builtin_object_size(d, 1));\n",
3913            "  __builtin___memset_chk(d, 0, n, 8);\n",
3914            "}\n",
3915        ));
3916        assert!(text.contains("call @__memcpy_chk("), "{text}");
3917        assert!(text.contains("call @__strcpy_chk("), "{text}");
3918        assert!(text.contains("call @__memset_chk("), "{text}");
3919        assert!(text.contains("iconst.i64 8"), "the object size reaches the call: {text}");
3920        assert!(!text.contains("__builtin_"), "the prefix is not part of any name here:\n{text}");
3921    }
3922
3923    /// A checking call whose object size says nothing is known is the plain library call.
3924    ///
3925    /// That is the whole of the folding half of the family. The checking function reads the all
3926    /// ones value as do not check, so the call it was going to make is the function it guards with
3927    /// an argument nobody reads on the end of it, and gcc drops the argument and calls the plain
3928    /// function at every level including `-O0`. Where the size is a real number the checking call
3929    /// stands, because the check is the point.
3930    #[test]
3931    fn a_checking_call_whose_size_says_nothing_is_known_is_the_plain_library_call() {
3932        let text = ir(concat!(
3933            "extern char *p;\n",
3934            "char d[8];\n",
3935            "void f(const char *s, unsigned long n) {\n",
3936            "  __builtin___memcpy_chk(d, s, n, __builtin_object_size(d, 0));\n",
3937            "  __builtin___memcpy_chk(p, s, n, __builtin_object_size(p, 0));\n",
3938            "  __builtin___strcpy_chk(p, s, __builtin_object_size(p, 0));\n",
3939            "  __builtin___stpncpy_chk(p, s, n, __builtin_object_size(p, 0));\n",
3940            "  __builtin___sprintf_chk(p, 1, __builtin_object_size(p, 0), s);\n",
3941            "}\n",
3942        ));
3943
3944        // The destination whose object is in sight keeps its check, size and all.
3945        assert!(
3946            text.contains("call @__memcpy_chk(%2, %0, %1, %3) : (ptr, ptr, i64, i64)"),
3947            "{text}"
3948        );
3949
3950        // The three whose object is not lose the argument and the name along with it. The type of
3951        // the call goes with them, which is what says the argument is gone rather than ignored.
3952        assert!(text.contains("call @memcpy(%6, %0, %1) : (ptr, ptr, i64) -> ptr"), "{text}");
3953        assert!(text.contains("call @strcpy(%10, %0) : (ptr, ptr) -> ptr"), "{text}");
3954        assert!(text.contains("call @stpncpy(%14, %0, %1) : (ptr, ptr, i64) -> ptr"), "{text}");
3955
3956        // The formatted one never folds, whatever the size says, because refusing a `%n` in a
3957        // writable format is the other half of what it was asked to do.
3958        assert!(text.contains("call @__sprintf_chk("), "{text}");
3959
3960        // Nothing is left behind in the instructions either. The size the folded calls no longer
3961        // take is a constant nobody reads, and no instruction is written for one.
3962        let asm = asm(concat!(
3963            "void f(char *p, const char *s, unsigned long n) {\n",
3964            "  __builtin___memcpy_chk(p, s, n, __builtin_object_size(p, 0));\n",
3965            "}\n",
3966        ));
3967        assert!(asm.contains("call\tmemcpy"), "{asm}");
3968        assert!(!asm.contains("$-1"), "the size that went away leaves no instruction:\n{asm}");
3969    }
3970
3971    /// The `v` spellings take a `__builtin_va_list`, which is the first type in the table the
3972    /// target chooses the shape of rather than the width of.
3973    ///
3974    /// On x86-64 it is an array of one, so what the prototype has to say is the pointer that
3975    /// array decays to, which is the same adjustment C makes to any parameter written as an array
3976    /// and is what a `va_list` parameter already holds. A prototype that kept the array would be
3977    /// one no argument could ever match.
3978    #[test]
3979    fn the_v_spellings_of_the_chk_family_take_the_list_a_va_list_parameter_holds() {
3980        let text = ir(concat!(
3981            "char d[64];\n",
3982            "int f(const char *fmt, ...) {\n",
3983            "  __builtin_va_list ap;\n",
3984            "  __builtin_va_start(ap, fmt);\n",
3985            "  int n = __builtin___vsprintf_chk(d, 1, __builtin_object_size(d, 0), fmt, ap);\n",
3986            "  __builtin_va_end(ap);\n",
3987            "  return n;\n",
3988            "}\n",
3989        ));
3990        assert!(text.contains("call @__vsprintf_chk("), "{text}");
3991        assert!(text.contains("iconst.i64 64"), "the object size reaches the call: {text}");
3992    }
3993
3994    /// The absolute value family is four instructions and not a call, whoever declared the name.
3995    ///
3996    /// `abs`, `labs` and `llabs` are reserved to the implementation, so a program that writes one
3997    /// means the one the C library promises and the compiler is allowed to know what it does. The
3998    /// program in `gcc.c-torture/execute/20021127-1.c` is the one that insists: it defines `llabs`
3999    /// to abort and expects the call not to reach it. Measured against gcc 16.2.0, which writes a
4000    /// `neg` and a `cmovns` and never calls the definition either.
4001    ///
4002    /// The most negative value comes back as itself, which is what the arithmetic gives and what
4003    /// gcc's pair of instructions gives, and C says the answer is undefined there.
4004    #[test]
4005    fn the_absolute_value_family_is_the_magnitude_and_not_a_call() {
4006        let text = body(concat!(
4007            "long long llabs(long long);\n",
4008            "long long f(long long x) { return llabs(x); }\n",
4009        ));
4010        assert!(text.contains("%1 = iconst.i64 63"), "{text}");
4011        assert!(text.contains("%2 = ashr %0, %1"), "{text}");
4012        assert!(text.contains("%3 = xor %0, %2"), "{text}");
4013        assert!(text.contains("%4 = sub %3, %2"), "{text}");
4014        assert!(!text.contains("call"), "the call does not happen:\n{text}");
4015
4016        // The narrower two, whose width comes from the type the library gives the name and not
4017        // from anything at the call.
4018        let text = body("int abs(int);\nint f(int x) { return abs(x); }\n");
4019        assert!(text.contains("iconst.i32 31"), "{text}");
4020        let text = body("long labs(long);\nlong f(long x) { return labs(x); }\n");
4021        assert!(text.contains("iconst.i64 63"), "{text}");
4022
4023        // The prefixed spelling is the same node, and it is what a program writes to reach the
4024        // library's meaning where the plain name has been taken.
4025        let text = body("long long f(long long x) { return __builtin_llabs(x); }\n");
4026        assert!(!text.contains("call"), "{text}");
4027
4028        // A definition of the name in the same file changes nothing, which is the whole point.
4029        let text = ir(concat!(
4030            "long long llabs(long long b);\n",
4031            "long long g(long long x) { return llabs(x); }\n",
4032            "long long llabs(long long b) { return 7; }\n",
4033        ));
4034        assert!(!text.contains("call @llabs"), "{text}");
4035    }
4036
4037    /// A byte swap is one instruction and not a call, and nothing had to declare it.
4038    ///
4039    /// SQLite writes these for its page headers and glibc's `<endian.h>` defines `htobe32` and its
4040    /// neighbours as exactly these, so a program that reads a file format reaches one without ever
4041    /// naming it. There is no object file anywhere that defines `__builtin_bswap32`, so a call left
4042    /// standing here would not link.
4043    #[test]
4044    fn a_byte_swap_is_arithmetic_and_not_a_call() {
4045        let text = body("unsigned f(unsigned x) { return __builtin_bswap32(x); }\n");
4046        assert_eq!(text, "block0(%0: i32):\n    %1 = bswap %0\n    return %1\n");
4047
4048        // The argument is converted by the prototype the way any other call's would be, so the
4049        // swap happens at the width the name says and not at the width the program wrote.
4050        let text = body("unsigned f(unsigned char c) { return __builtin_bswap32(c); }\n");
4051        assert!(text.contains("zext.i32 %0"), "widened first: {text}");
4052        assert!(text.contains("bswap %1"), "and swapped at four bytes: {text}");
4053    }
4054
4055    /// Each of the three reverses in the width its name says, which is the type of the node.
4056    ///
4057    /// The width matters more here than it looks. `__builtin_bswap16` is the two bytes of a
4058    /// `uint16_t` exchanged, and if the node came out at the machine's width instead then the bits
4059    /// above the value would be dragged into the answer and the result would be zero.
4060    #[test]
4061    fn the_byte_swaps_reverse_at_the_width_their_name_says() {
4062        for (name, ty, width) in [
4063            ("__builtin_bswap16", "unsigned short", "i16"),
4064            ("__builtin_bswap32", "unsigned", "i32"),
4065            ("__builtin_bswap64", "unsigned long long", "i64"),
4066        ] {
4067            let source = format!("{ty} f({ty} x) {{ return {name}(x); }}\n");
4068            let text = body(&source);
4069            assert_eq!(
4070                text,
4071                format!("block0(%0: {width}):\n    %1 = bswap %0\n    return %1\n"),
4072                "{name}"
4073            );
4074        }
4075    }
4076
4077    /// The three bit counts the IR has an instruction for are that instruction and not a call.
4078    ///
4079    /// Eighteen rows of `features.toml` come out of six questions, and three of the six are one
4080    /// instruction each. The kernel's bitmap search is built on them, ffmpeg counts leading zeroes
4081    /// in its bitstream reader and SQLite uses one to size a page, so a call left standing here
4082    /// would not link against anything and would be slow if it did.
4083    #[test]
4084    fn the_bit_counts_are_instructions_and_not_calls() {
4085        let text = body("int f(unsigned x) { return __builtin_clz(x); }\n");
4086        assert_eq!(text, "block0(%0: i32):\n    %1 = ctlz %0\n    return %1\n");
4087
4088        let text = body("int f(unsigned x) { return __builtin_ctz(x); }\n");
4089        assert_eq!(text, "block0(%0: i32):\n    %1 = cttz %0\n    return %1\n");
4090
4091        let text = body("int f(unsigned x) { return __builtin_popcount(x); }\n");
4092        assert_eq!(text, "block0(%0: i32):\n    %1 = ctpop %0\n    return %1\n");
4093    }
4094
4095    /// The width counted is the operand's and the width answered is `int`, which are two different
4096    /// things at every spelling but the narrowest.
4097    ///
4098    /// This is the mistake the family invites. `__builtin_clz` of a value counts the leading zeroes
4099    /// of it narrowed to `unsigned int` and `__builtin_clzll` counts them at sixty four bits, and
4100    /// those are different numbers for the same value. What decides it is the prototype the row
4101    /// carries, so the count happens after the conversion and the narrowing back to `int` happens
4102    /// after the count.
4103    #[test]
4104    fn the_bit_counts_ask_about_the_width_their_name_says() {
4105        let text = body("int f(unsigned long long x) { return __builtin_clzll(x); }\n");
4106        assert!(text.starts_with("block0(%0: i64):"), "counted at eight bytes: {text}");
4107        assert!(text.contains("%1 = ctlz %0"), "{text}");
4108        assert!(text.contains("trunc.i32 %1"), "and answered in an int: {text}");
4109
4110        // The same value asked about at the narrower width, which converts first and so counts
4111        // something else.
4112        let text = body("int f(unsigned long long x) { return __builtin_clz(x); }\n");
4113        assert!(text.contains("trunc.i32 %0"), "narrowed to what was asked about: {text}");
4114        assert!(text.contains("ctlz %1"), "and counted there: {text}");
4115
4116        let text = body("int f(unsigned long x) { return __builtin_popcountl(x); }\n");
4117        assert!(text.contains("%1 = ctpop %0"), "{text}");
4118        assert!(!text.contains("call"), "{text}");
4119    }
4120
4121    /// A parity is whether the count of set bits is odd, which is that count and its low bit.
4122    ///
4123    /// Not the machine's parity flag, which on x86-64 is over the low byte of a result and so is a
4124    /// different question, and not the count itself, since C says the answer is zero or one.
4125    #[test]
4126    fn a_parity_is_the_low_bit_of_the_set_bit_count() {
4127        let text = body("int f(unsigned x) { return __builtin_parity(x); }\n");
4128        assert!(text.contains("%1 = ctpop %0"), "{text}");
4129        assert!(text.contains("iconst.i32 1"), "{text}");
4130        assert!(text.contains("and %1, %2"), "the low bit of it: {text}");
4131    }
4132
4133    /// `__builtin_ffs` is the trailing zero count and one, kept only when there was a bit to find.
4134    ///
4135    /// The one in the family defined at zero, where it answers zero. Written as a mask rather than
4136    /// as a branch: the count and the comparison do not depend on each other and both are cheap, so
4137    /// a branch would buy nothing and cost two blocks and a join.
4138    #[test]
4139    fn the_first_set_bit_is_one_based_and_zero_for_a_zero() {
4140        let text = body("int f(int x) { return __builtin_ffs(x); }\n");
4141        assert!(text.contains("%1 = cttz %0"), "{text}");
4142        assert!(text.contains("%4 = add %1, %2"), "one more than the count: {text}");
4143        assert!(text.contains("%5 = icmp ne %0, %3"), "whether there was a bit at all: {text}");
4144        assert!(text.contains("%7 = sub %3, %6"), "spread to a mask: {text}");
4145        assert!(text.contains("%8 = and %4, %7"), "and kept only then: {text}");
4146        assert!(!text.contains("br_if"), "no branch: {text}");
4147    }
4148
4149    /// `__builtin_clrsb` is how many bits below the sign bit repeat it, which is a leading zero
4150    /// count of the value folded onto its own sign.
4151    ///
4152    /// Exclusive or with the sign spread over every bit turns a negative value into its complement
4153    /// and leaves one that is not negative alone, so in both cases the top bit is clear and there
4154    /// is one zero above the highest bit that does not repeat the sign. The answer is one less
4155    /// than that count, and the shift left is what takes the one off, with the low bit set on the
4156    /// way so that zero and minus one have something to count: both of them fold to a word with no
4157    /// bits in it, which is the one input a leading zero count says nothing about.
4158    #[test]
4159    fn the_redundant_sign_bit_count_is_instructions_and_not_a_call() {
4160        let text = body("int f(int x) { return __builtin_clrsb(x); }\n");
4161        assert!(text.contains("%1 = iconst.i32 31"), "{text}");
4162        assert!(text.contains("%2 = ashr %0, %1"), "the sign over every bit: {text}");
4163        assert!(text.contains("%3 = xor %0, %2"), "folded onto it: {text}");
4164        assert!(text.contains("%5 = shl %3, %4"), "one less than the count: {text}");
4165        assert!(text.contains("%6 = or %5, %4"), "with something to count at zero: {text}");
4166        assert!(text.contains("%7 = ctlz %6"), "{text}");
4167        assert!(!text.contains("call"), "{text}");
4168        assert!(!text.contains("br_if"), "no branch: {text}");
4169    }
4170
4171    /// The unsigned four are the same four instructions answering in the unsigned type.
4172    ///
4173    /// Which on a two's complement machine is the same bits, so what this checks is that the type
4174    /// of the answer is the unsigned one. The reason the family exists is the most negative value,
4175    /// whose magnitude is not representable in the signed type and is representable in this one.
4176    #[test]
4177    fn the_unsigned_absolute_value_family_answers_in_the_unsigned_type() {
4178        let text = body("unsigned f(int x) { return __builtin_uabs(x); }\n");
4179        assert!(text.contains("%1 = iconst.i32 31"), "{text}");
4180        assert!(text.contains("%4 = sub %3, %2"), "{text}");
4181        assert!(!text.contains("call"), "nothing declares uabs, so a call would not link: {text}");
4182
4183        let text = body("unsigned long long f(long long x) { return __builtin_ullabs(x); }\n");
4184        assert!(text.contains("iconst.i64 63"), "at the width the name says: {text}");
4185
4186        // The answer is the unsigned type and not the signed one, which is what a comparison
4187        // against it is decided by.
4188        let text = body("int f(int x) { return __builtin_uabs(x) > 2147483647u; }\n");
4189        assert!(text.contains("icmp ugt"), "compared unsigned: {text}");
4190    }
4191
4192    /// `intmax_t` is not a fixed type, so the two widest spellings ask the target what it is.
4193    ///
4194    /// `long` where that is sixty four bits wide and `long long` where it is not, which is the rule
4195    /// `rucc_pp::predef` writes `__INTMAX_TYPE__` out of. The three targets here are all LP64, so
4196    /// the answer is `long` and the shift is sixty three, and the point of the test is that the
4197    /// signature was understood at all rather than refused for naming a type the table could not
4198    /// spell.
4199    #[test]
4200    fn the_widest_absolute_value_is_whichever_type_the_target_makes_intmax_t() {
4201        let text = body("long f(long x) { return __builtin_imaxabs(x); }\n");
4202        assert!(text.contains("iconst.i64 63"), "{text}");
4203        assert!(text.contains("%4 = sub %3, %2"), "{text}");
4204        assert!(!text.contains("call"), "{text}");
4205
4206        let text = body("unsigned long f(long x) { return __builtin_umaxabs(x); }\n");
4207        assert!(text.contains("iconst.i64 63"), "{text}");
4208        assert!(!text.contains("call"), "{text}");
4209    }
4210
4211    /// The `_p` spellings ask the same question, write nothing, and do not evaluate the third
4212    /// argument.
4213    ///
4214    /// gcc says the third argument is there for its type alone, so a call is two operands and a
4215    /// type by the time it reaches the IR. What the type decides is the same thing it decides for
4216    /// the three that write: whether the exact answer would have fit there, which is why the
4217    /// second call below is done at a wider width than the first.
4218    #[test]
4219    fn an_overflow_predicate_writes_nothing_and_answers_the_bit_the_check_would() {
4220        let text =
4221            body("int f(int a, int b) { return __builtin_add_overflow_p(a, b, (int) 0); }\n");
4222        assert!(text.contains("%2, %3 = sadd_overflow.(i32, i1) %0, %1"), "{text}");
4223        assert!(!text.contains("store"), "nothing is written: {text}");
4224        assert!(!text.contains("call"), "{text}");
4225
4226        // A wider destination is a wider arithmetic, and the narrowing test that goes with it is
4227        // what says whether the answer got there, exactly as for the spelling that stores.
4228        let text =
4229            body("int f(int a, int b) { return __builtin_mul_overflow_p(a, b, (long long) 0); }\n");
4230        assert!(text.contains("smul_overflow.(i64, i1)"), "{text}");
4231        assert!(!text.contains("store"), "{text}");
4232
4233        // The third argument is a value and not a pointer, and a side effect written in it does
4234        // not happen, because what the argument is there for is its type.
4235        let text = body(concat!(
4236            "int g(void);\n",
4237            "int f(int a, int b) { return __builtin_sub_overflow_p(a, b, g()); }\n",
4238        ));
4239        assert!(!text.contains("call @g"), "the third argument is not evaluated: {text}");
4240    }
4241
4242    /// The three overflow checks are arithmetic and a flag, and not a call to anything.
4243    ///
4244    /// gcc has emitted these since 5.0 and there is no object file that defines one, so a call left
4245    /// standing here would not link. SQLite reaches all three within twenty lines of each other, in
4246    /// `sqlite3AddInt64` and its two neighbours, which is the reason they were done now.
4247    ///
4248    /// The IR instruction answers two things at once, the wrapped value and whether it wrapped,
4249    /// which is a shape nothing else in the IR has. The store is the builtin writing the answer
4250    /// through the pointer it was handed.
4251    #[test]
4252    fn an_overflow_check_is_arithmetic_and_not_a_call() {
4253        let text =
4254            body("int f(int a, int b, int *r) { return __builtin_add_overflow(a, b, r); }\n");
4255        assert!(text.contains("%3, %4 = sadd_overflow.(i32, i1) %0, %1"), "{text}");
4256        assert!(text.contains("store %3 -> %2"), "{text}");
4257        assert!(!text.contains("call"), "{text}");
4258
4259        let text =
4260            body("int f(int a, int b, int *r) { return __builtin_sub_overflow(a, b, r); }\n");
4261        assert!(text.contains("ssub_overflow.(i32, i1) %0, %1"), "{text}");
4262
4263        let text =
4264            body("int f(int a, int b, int *r) { return __builtin_mul_overflow(a, b, r); }\n");
4265        assert!(text.contains("smul_overflow.(i32, i1) %0, %1"), "{text}");
4266
4267        // Unsigned operands get the unsigned form, which is a different question about the same
4268        // arithmetic: an unsigned sum wraps where a signed one of the same bits does not.
4269        let text = body(
4270            "int f(unsigned a, unsigned b, unsigned *r) { return __builtin_add_overflow(a, b, r); }\n",
4271        );
4272        assert!(text.contains("uadd_overflow.(i32, i1) %0, %1"), "{text}");
4273    }
4274
4275    /// The arithmetic happens at a type that holds every value all three written types can hold.
4276    ///
4277    /// That is what makes the check exact. `unsigned int` and `int` in one call need thirty three
4278    /// bits between them, so the add is done at sixty four with each operand extended the way its
4279    /// own signedness says: the unsigned one zero extended, the signed one sign extended. Sign
4280    /// extending the unsigned one would turn three billion into a negative number before the
4281    /// addition ever saw it.
4282    #[test]
4283    fn an_overflow_check_is_done_at_a_type_that_holds_every_operand() {
4284        let text = body(
4285            "int f(unsigned a, int b, long long *r) { return __builtin_add_overflow(a, b, r); }\n",
4286        );
4287        assert!(text.contains("%3 = zext.i64 %0"), "the unsigned operand keeps its value: {text}");
4288        assert!(text.contains("%4 = sext.i64 %1"), "and so does the signed one: {text}");
4289        assert!(text.contains("sadd_overflow.(i64, i1) %3, %4"), "{text}");
4290
4291        // Three types that agree need no extension at all, which is what nearly every real call
4292        // is written as.
4293        let text = body(
4294            "int f(long long a, long long b, long long *r) { return __builtin_mul_overflow(a, b, r); }\n",
4295        );
4296        assert!(text.contains("smul_overflow.(i64, i1) %0, %1"), "{text}");
4297        assert!(!text.contains("sext."), "{text}");
4298        // The one widening left is the answer, which is a bit becoming the `int` C says it is.
4299        assert!(!text.contains("zext.i64"), "{text}");
4300    }
4301
4302    /// The wrapped answer is written through the pointer whether or not it fit.
4303    ///
4304    /// That is gcc's rule and it is what makes the builtin usable as a wrapping add with a flag on
4305    /// the side. A destination narrower than the arithmetic is narrowed and widened back, and the
4306    /// answer being different is the second half of the test: the instruction says whether the
4307    /// arithmetic itself needed more room, and the round trip says whether what came out survived
4308    /// the trip down to where it was going.
4309    #[test]
4310    fn an_overflow_check_writes_the_wrapped_answer_whether_or_not_it_fit() {
4311        let text =
4312            body("int f(int a, int b, char *r) { return __builtin_sub_overflow(a, b, r); }\n");
4313        assert!(text.contains("%3, %4 = ssub_overflow.(i32, i1) %0, %1"), "{text}");
4314        assert!(text.contains("%5 = trunc.i8 %3"), "narrowed to where it goes: {text}");
4315        assert!(text.contains("%6 = sext.i32 %5"), "and back: {text}");
4316        assert!(text.contains("%7 = icmp ne %6, %3"), "which is whether it fit: {text}");
4317        assert!(text.contains("store %5 -> %2"), "the narrowed value is stored either way: {text}");
4318        assert!(text.contains("%8 = or %4, %7"), "and either bit is an overflow: {text}");
4319    }
4320
4321    /// A call needing more than the widest type there is compiles, by not asking for such a type.
4322    ///
4323    /// One way to reach it: an unsigned `__int128` mixed with a signed type, which needs a hundred
4324    /// and twenty nine bits to represent both and so has nowhere left to go. That used to be refused
4325    /// by name. It is done now by carrying the sign of each operand alongside its value rather than
4326    /// inside it, which is what gcc does, so all three of the family compile for that mix.
4327    #[test]
4328    fn a_call_needing_more_than_the_widest_type_still_compiles() {
4329        for name in ["add", "sub", "mul"] {
4330            let source = format!(
4331                "int f(unsigned __int128 a, long long b, __int128 *r) {{\n    \
4332                 return __builtin_{name}_overflow(a, b, r);\n}}\n"
4333            );
4334            let mut opts = options();
4335            opts.emit = EmitKind::MirFinal;
4336            assert!(!run(&opts, &source).failed(), "{name} was refused or stopped the back end");
4337        }
4338    }
4339
4340    /// An operand that is not an integer at all is the older message, from the type checking every
4341    /// type generic builtin shares.
4342    #[test]
4343    fn an_overflow_check_over_something_that_is_not_an_integer_says_so() {
4344        let messages =
4345            errors("int f(double a, int b, int *r) { return __builtin_add_overflow(a, b, r); }\n");
4346        assert!(messages.iter().any(|line| line.contains("E0671")), "{messages:?}");
4347
4348        let messages =
4349            errors("int f(int a, int b, double *r) { return __builtin_add_overflow(a, b, r); }\n");
4350        assert!(messages.iter().any(|line| line.contains("E0671")), "{messages:?}");
4351    }
4352
4353    /// An ordered access is an ordered access in the IR, with the ordering the program wrote.
4354    ///
4355    /// Which is the point of the node existing at all. An ordering is not an argument anything is
4356    /// passed, it is a thing the IR says about an access, so the number in the source is read once
4357    /// in the front end and after that the ordering travels on the instruction where every pass
4358    /// that moves code can see it.
4359    ///
4360    /// SQLite is why these are done: `AtomicLoad` and `AtomicStore` in `sqlite3.c` are
4361    /// `__atomic_load_n` and `__atomic_store_n` at the relaxed ordering, and there are thirty five
4362    /// calls to the pair.
4363    #[test]
4364    fn an_ordered_access_is_ordered_in_the_ir() {
4365        let text = body("int f(int *p) { return __atomic_load_n(p, 0); }\n");
4366        assert!(text.contains("atomic_load.i32 %0, align 4, relaxed"), "{text}");
4367
4368        let text = body("long f(long *p) { return __atomic_load_n(p, 2); }\n");
4369        assert!(text.contains("atomic_load.i64 %0, align 8, acquire"), "{text}");
4370
4371        let text = body("void f(int *p, int v) { __atomic_store_n(p, v, 3); }\n");
4372        assert!(text.contains("atomic_store %1 -> %0, align 4, release"), "{text}");
4373
4374        let text = body("void f(int *p, int v) { __atomic_store_n(p, v, 5); }\n");
4375        assert!(text.contains("atomic_store %1 -> %0, align 4, seq_cst"), "{text}");
4376
4377        // The value is converted to what the pointer points at before it is stored, which is what
4378        // the call would have done if it had a prototype to convert against.
4379        let text = body("void f(char *p, int v) { __atomic_store_n(p, v, 0); }\n");
4380        assert!(text.contains("trunc.i8 %1"), "{text}");
4381        assert!(text.contains("atomic_store %2 -> %0, align 1, relaxed"), "{text}");
4382    }
4383
4384    /// On this machine the ordered access is the plain instruction, except at the strongest
4385    /// ordering of a store.
4386    ///
4387    /// x86-64 is total store order: every load is already an acquire and every store is already a
4388    /// release, and an aligned access no wider than a word is indivisible whether or not anybody
4389    /// asked. So the whole family is `mov` and the one thing the machine does not give away is a
4390    /// store staying in front of a later load, which is `mfence` behind the store. Every line below
4391    /// is what gcc 16.2.0 writes for the same function.
4392    #[test]
4393    fn an_ordered_access_is_the_plain_instruction_on_this_machine() {
4394        let text = asm("int f(int *p) { return __atomic_load_n(p, 5); }\n");
4395        assert!(text.contains("movl\t(%rdi), %eax"), "{text}");
4396        assert!(!text.contains("mfence"), "a load needs no barrier here: {text}");
4397
4398        let text = asm("void f(int *p, int v) { __atomic_store_n(p, v, 3); }\n");
4399        assert!(text.contains("movl\t%esi, (%rdi)"), "{text}");
4400        assert!(!text.contains("mfence"), "a release store needs no barrier here: {text}");
4401
4402        let text = asm("void f(int *p, int v) { __atomic_store_n(p, v, 5); }\n");
4403        let (before, after) = text.split_once("mfence").expect("a barrier: {text}");
4404        assert!(before.contains("movl\t%esi, (%rdi)"), "the store comes first: {text}");
4405        assert!(!after.contains("movl"), "and nothing else is between them: {text}");
4406    }
4407
4408    /// A barrier is one instruction at the strongest ordering and no instruction below it.
4409    ///
4410    /// The same reasoning the other way round. An acquire, a release and an acquire release fence
4411    /// are already true of every program running on this machine, and what a program wanted from
4412    /// one is that the compiler not move accesses across it, which is already so by the time any
4413    /// instruction is picked. Sequential consistency is the one that costs something.
4414    ///
4415    /// `__sync_synchronize` is the older family's spelling of the strongest one and compiles to
4416    /// exactly the same instruction, which is what SQLite calls twice in `sqlite3.c`.
4417    #[test]
4418    fn a_barrier_is_one_instruction_at_the_strongest_ordering_and_none_below_it() {
4419        assert!(asm("void f(void) { __atomic_thread_fence(5); }\n").contains("mfence"));
4420        assert!(asm("void f(void) { __sync_synchronize(); }\n").contains("mfence"));
4421
4422        for weaker in ["1", "2", "3", "4"] {
4423            let source = format!("void f(void) {{ __atomic_thread_fence({weaker}); }}\n");
4424            assert!(!asm(&source).contains("mfence"), "{weaker} costs nothing here");
4425        }
4426    }
4427
4428    /// The three x86 fences under gcc's names are that same barrier at that same ordering.
4429    ///
4430    /// Exact for `mfence` and stronger than asked for the other two, which is a safe answer: a
4431    /// program that wanted its stores ordered gets that and more. Narrowing the two is worth doing
4432    /// once an instruction can be named from there, which is the note the shipped `xmmintrin.h`
4433    /// already carries at `_mm_sfence`.
4434    ///
4435    /// Each carries a signature, so an argument written on one is reported like an argument
4436    /// written on any other call, which is the whole reason they have one.
4437    #[test]
4438    fn the_three_x86_fences_are_the_barrier_the_strongest_ordering_gives() {
4439        for name in ["__builtin_ia32_sfence", "__builtin_ia32_lfence", "__builtin_ia32_mfence"] {
4440            let source = format!("void f(void) {{ {name}(); }}\n");
4441            assert!(asm(&source).contains("mfence"), "{name} is a barrier");
4442            let text = body(&source);
4443            assert!(text.contains("fence seq_cst"), "{name}: {text}");
4444        }
4445
4446        let result = run(&options(), "void f(void) { __builtin_ia32_sfence(1); }\n");
4447        assert_eq!(result.messages.len(), 1, "{:?}", result.messages);
4448        assert!(result.messages[0].contains("too many arguments"), "{:?}", result.messages);
4449    }
4450
4451    /// The four compare and exchange names are one IR instruction producing two values.
4452    ///
4453    /// Which of the two the expression answers is the difference between three of the four names,
4454    /// and the fourth difference is the C11 pair writing what they found back through the pointer
4455    /// they were handed, which is the branch after the instruction.
4456    #[test]
4457    fn a_compare_and_exchange_is_one_instruction_answering_two_things() {
4458        // The older family, whose two names are the same instruction read two ways. Neither has a
4459        // memory order argument and both are a full barrier, which is what `seq_cst` says.
4460        let text =
4461            body("int f(int *p, int e, int d) { return __sync_val_compare_and_swap(p, e, d); }\n");
4462        assert!(text.contains("%3, %4 = cmpxchg.(i32, i1) %0, %1, %2, align 4, seq_cst"), "{text}");
4463        assert!(text.contains("return %3"), "the value it found: {text}");
4464
4465        let text =
4466            body("int f(int *p, int e, int d) { return __sync_bool_compare_and_swap(p, e, d); }\n");
4467        assert!(text.contains("%3, %4 = cmpxchg.(i32, i1) %0, %1, %2, align 4, seq_cst"), "{text}");
4468        assert!(text.contains("zext.i32 %4"), "whether it happened: {text}");
4469
4470        // The C11 form, whose value expected arrives by pointer and is read before the exchange,
4471        // and whose answer is whether it happened. The write back is on the path where it did not.
4472        let text = body(
4473            "int f(int *p, int *e, int d) { return __atomic_compare_exchange_n(p, e, d, 0, 4, 2); }\n",
4474        );
4475        assert!(text.contains("%3 = load.i32 %1, align 4"), "{text}");
4476        assert!(text.contains("%4, %5 = cmpxchg.(i32, i1) %0, %3, %2, align 4, acq_rel"), "{text}");
4477        assert!(text.contains("br_if %5, block2, block1"), "{text}");
4478        assert!(text.contains("store %4 -> %1, align 4"), "{text}");
4479
4480        // And the form that takes the value to put there by pointer as well, which is one more
4481        // read and is otherwise the same node.
4482        let text = body(
4483            "int f(int *p, int *e, int *d) { return __atomic_compare_exchange(p, e, d, 0, 5, 5); }\n",
4484        );
4485        assert!(text.contains("%3 = load.i32 %1, align 4"), "{text}");
4486        assert!(text.contains("%4 = load.i32 %2, align 4"), "{text}");
4487        assert!(text.contains("%5, %6 = cmpxchg.(i32, i1) %0, %3, %4, align 4, seq_cst"), "{text}");
4488    }
4489
4490    /// On this machine it is `lock cmpxchg`, at the width of the object and at every ordering.
4491    ///
4492    /// The `lock` is what makes the whole of it one step as far as every other processor is
4493    /// concerned, and it is also what makes the instruction a full barrier, which is why the
4494    /// ordering the program wrote changes nothing in what is written here. Every line below is what
4495    /// gcc 16.2.0 writes for the same function.
4496    #[test]
4497    fn a_compare_and_exchange_is_a_locked_instruction_at_the_width_of_the_object() {
4498        let widths = [("char", "b", "%dl"), ("short", "w", "%dx"), ("int", "l", "%edx")];
4499        for (ty, suffix, reg) in widths {
4500            let source = format!(
4501                "int f({ty} *p, {ty} e, {ty} d) {{ return __sync_bool_compare_and_swap(p, e, d); }}\n"
4502            );
4503            let text = asm(&source);
4504            assert!(text.contains("\tlock\n"), "{ty}: {text}");
4505            assert!(text.contains(&format!("cmpxchg{suffix}\t{reg}, (%rdi)")), "{ty}: {text}");
4506            assert!(text.contains("sete\t"), "{ty}: {text}");
4507        }
4508        let source =
4509            "int f(long *p, long e, long d) { return __sync_bool_compare_and_swap(p, e, d); }\n";
4510        assert!(asm(source).contains("cmpxchgq\t%rdx, (%rdi)"), "{}", asm(source));
4511
4512        // The ordering the program asked for changes nothing, because a locked instruction on this
4513        // machine orders everything whatever it was asked for, so there is never a barrier beside
4514        // it either.
4515        for order in ["0", "2", "3", "4", "5"] {
4516            let call = format!("__atomic_compare_exchange_n(p, e, d, 0, {order}, 0)");
4517            let source = format!("int f(int *p, int *e, int d) {{ return {call}; }}\n");
4518            let text = asm(&source);
4519            assert!(text.contains("cmpxchgl\t"), "{order}: {text}");
4520            assert!(!text.contains("mfence"), "{order} needs no barrier here: {text}");
4521        }
4522    }
4523
4524    /// A read modify write is one IR instruction, and a name that asks for the value afterwards is
4525    /// that instruction and one more operation.
4526    ///
4527    /// The instruction answers what was there before, which is the convention every machine and
4528    /// every language in this area uses. Half the names in the family ask for the value afterwards
4529    /// instead, and that is the answer and the operand put together again, which is arithmetic on
4530    /// two values already in registers rather than a second flavour of the instruction.
4531    ///
4532    /// The two lock names are here too. They are not read modify writes in the same sense: one is
4533    /// an exchange and the other is a store of a zero, and what makes them a pair is the ordering,
4534    /// which is the one place in the older family that is not sequential consistency.
4535    #[test]
4536    fn a_read_modify_write_is_one_instruction_and_the_arithmetic_a_name_asks_for() {
4537        let text = body("int f(int *p, int v) { return __atomic_fetch_add(p, v, 5); }\n");
4538        assert!(text.contains("%2 = atomic_rmw.i32 add %0, %1, align 4, seq_cst"), "{text}");
4539        assert!(text.contains("return %2"), "the value that was there: {text}");
4540
4541        let text = body("int f(int *p, int v) { return __atomic_add_fetch(p, v, 5); }\n");
4542        assert!(text.contains("%2 = atomic_rmw.i32 add %0, %1, align 4, seq_cst"), "{text}");
4543        assert!(text.contains("%3 = add %2, %1"), "and the value afterwards: {text}");
4544
4545        let text = body("int f(int *p, int v) { return __atomic_sub_fetch(p, v, 5); }\n");
4546        assert!(text.contains("%2 = atomic_rmw.i32 sub %0, %1, align 4, seq_cst"), "{text}");
4547        assert!(text.contains("%3 = sub %2, %1"), "{text}");
4548
4549        // The older family, which passes no ordering and is a full barrier.
4550        let text = body("int f(int *p, int v) { return __sync_fetch_and_sub(p, v); }\n");
4551        assert!(text.contains("%2 = atomic_rmw.i32 sub %0, %1, align 4, seq_cst"), "{text}");
4552
4553        // The exchange, and the older family's spelling of it, which is taking a lock and so is an
4554        // acquire rather than the full barrier the rest of that family is.
4555        let text = body("int f(int *p, int v) { return __atomic_exchange_n(p, v, 5); }\n");
4556        assert!(text.contains("%2 = atomic_rmw.i32 xchg %0, %1, align 4, seq_cst"), "{text}");
4557
4558        let text = body("int f(int *p, int v) { return __sync_lock_test_and_set(p, v); }\n");
4559        assert!(text.contains("%2 = atomic_rmw.i32 xchg %0, %1, align 4, acquire"), "{text}");
4560
4561        // Giving the lock back, which is one of the two names in the family that is handed no value
4562        // to put there, because what it puts there is a zero.
4563        let text = body("void f(int *p) { __sync_lock_release(p); }\n");
4564        assert!(text.contains("release"), "{text}");
4565        assert!(text.contains("%1 = iconst.i32 0"), "{text}");
4566
4567        // And with something after the pointer, which is the list of variables the call promises to
4568        // protect rather than a value to write. Reading it as a value would store whatever the
4569        // caller happened to name there, which is the one thing giving a lock back must not do.
4570        let text = body("void f(int *p, int guard) { __sync_lock_release(p, guard); }\n");
4571        assert!(text.contains("%2 = iconst.i32 0"), "{text}");
4572        assert!(text.contains("atomic_store %2 -> %0, align 4, release"), "{text}");
4573
4574        // The bitwise four, which look no different here from the arithmetic ones: what the machine
4575        // has an instruction for is a question further down and this level does not ask it.
4576        let text = body("int f(int *p, int v) { return __atomic_fetch_and(p, v, 5); }\n");
4577        assert!(text.contains("%2 = atomic_rmw.i32 and %0, %1, align 4, seq_cst"), "{text}");
4578
4579        let text = body("int f(int *p, int v) { return __sync_or_and_fetch(p, v); }\n");
4580        assert!(text.contains("%2 = atomic_rmw.i32 or %0, %1, align 4, seq_cst"), "{text}");
4581        assert!(text.contains("%3 = or %2, %1"), "and the value afterwards: {text}");
4582
4583        // The nand, which is the one of the six that is two operations. The flip is an exclusive or
4584        // against every bit set because the IR has no not and that is what one is.
4585        let text = body("int f(int *p, int v) { return __atomic_nand_fetch(p, v, 5); }\n");
4586        assert!(text.contains("%2 = atomic_rmw.i32 nand %0, %1, align 4, seq_cst"), "{text}");
4587        assert!(text.contains("%3 = and %2, %1"), "{text}");
4588        assert!(text.contains("%4 = iconst.i32 -1"), "{text}");
4589        assert!(text.contains("%5 = xor %3, %4"), "{text}");
4590    }
4591
4592    /// The four operations with no instruction on this machine are a loop around `lock cmpxchg`.
4593    ///
4594    /// The shape is the one every architecture manual writes out by hand: read the word, work out
4595    /// what should be there instead, put it back if nothing else got in first, and go round again
4596    /// when something did. What is checked is that the loop is there at every width, that the
4597    /// operation is inside it, and that no `xchg` or `xadd` got used for something neither of them
4598    /// does.
4599    ///
4600    /// gcc 16.2.0 writes the same loop for the same functions, down to which register holds the
4601    /// value that was read.
4602    #[test]
4603    fn a_bitwise_read_modify_write_is_a_loop_around_the_compare_and_exchange() {
4604        let widths = [("char", "b", "%dl"), ("short", "w", "%dx"), ("int", "l", "%edx")];
4605        for (ty, suffix, reg) in widths {
4606            for (name, call, insn) in [
4607                ("and", "__atomic_fetch_and(p, v, 5)", "and"),
4608                ("or", "__sync_fetch_and_or(p, v)", "or"),
4609                ("xor", "__atomic_xor_fetch(p, v, 5)", "xor"),
4610            ] {
4611                let source = format!("{ty} f({ty} *p, {ty} v) {{ return {call}; }}\n");
4612                let text = asm(&source);
4613                assert!(text.contains("\tlock\n"), "{ty} {name}: {text}");
4614                assert!(
4615                    text.contains(&format!("cmpxchg{suffix}\t{reg}, (%rdi)")),
4616                    "{ty} {name}: {text}"
4617                );
4618                assert!(text.contains(&format!("{insn}{suffix}\t")), "{ty} {name}: {text}");
4619                // The tab matters on the second of these, since `cmpxchg` ends in the other name.
4620                assert!(!text.contains("\txadd"), "{ty} {name} is not an add: {text}");
4621                assert!(!text.contains("\txchg"), "{ty} {name} is not an exchange: {text}");
4622            }
4623        }
4624        let source = "long f(long *p, long v) { return __atomic_fetch_or(p, v, 5); }\n";
4625        assert!(asm(source).contains("cmpxchgq\t%rdx, (%rdi)"), "{}", asm(source));
4626
4627        // The nand, which puts two instructions inside the loop rather than one. The flip is an
4628        // exclusive or against every bit set in the IR and the folder turns that into the `not` the
4629        // machine has, which is what gcc writes here too.
4630        let text = asm("int f(int *p, int v) { return __sync_fetch_and_nand(p, v); }\n");
4631        assert!(text.contains("cmpxchgl\t"), "{text}");
4632        assert!(text.contains("andl\t"), "{text}");
4633        assert!(text.contains("notl\t"), "{text}");
4634    }
4635
4636    /// The three names that pass a value through a pointer are the same access and one plain one.
4637    ///
4638    /// They exist for an object too big to come back in a register, and the front end takes them at
4639    /// their word rather than folding them into the `_n` spellings, because the extra access is real:
4640    /// the caller handed over somewhere to read from or write into and that is where the value has
4641    /// to come from or go. Both of those accesses are plain. The object at the end of the caller's
4642    /// pointer is the caller's own and no other thread has its address, which is what the whole
4643    /// shape is for.
4644    #[test]
4645    fn an_access_through_a_second_pointer_is_the_same_access_and_one_more() {
4646        let text = body("void f(int *p, int *r) { __atomic_load(p, r, 5); }\n");
4647        assert!(text.contains("%2 = atomic_load.i32 %0, align 4, seq_cst"), "{text}");
4648        assert!(text.contains("store %2 -> %1, align 4"), "and out through the place: {text}");
4649
4650        let text = body("void f(int *p, int *v) { __atomic_store(p, v, 3); }\n");
4651        assert!(text.contains("%2 = load.i32 %1, align 4"), "in through the place: {text}");
4652        assert!(text.contains("atomic_store %2 -> %0, align 4, release"), "{text}");
4653
4654        // The exchange, which reads through one pointer and writes through another and is the same
4655        // instruction in between as the spelling that takes and answers values.
4656        let text = body("void f(int *p, int *v, int *r) { __atomic_exchange(p, v, r, 5); }\n");
4657        assert!(text.contains("%3 = load.i32 %1, align 4"), "{text}");
4658        assert!(text.contains("%4 = atomic_rmw.i32 xchg %0, %3, align 4, seq_cst"), "{text}");
4659        assert!(text.contains("store %4 -> %2, align 4"), "{text}");
4660    }
4661
4662    /// The flag pair is an exchange of one byte and a store of a zero over the same byte.
4663    ///
4664    /// One byte whatever the pointer was written as, which is the standard's reading rather than a
4665    /// liberty: the object is an `atomic_flag`, there is no other way to read or write one, so the
4666    /// type the pointer carries says nothing about the access and the width is the implementation's
4667    /// to fix. gcc 16.2.0 writes `xchgb` here through an `int *` too.
4668    ///
4669    /// The answer is a comparison against zero rather than the byte itself, because the type of the
4670    /// call is `_Bool` and a byte that is neither zero nor one is not one. gcc answers the raw byte,
4671    /// and the two agree wherever the flag is only ever touched through this pair.
4672    #[test]
4673    fn a_flag_is_an_exchange_of_one_byte_and_a_store_of_a_zero_over_the_same_byte() {
4674        for pointer in ["char", "int", "void"] {
4675            let source = format!("int f({pointer} *p) {{ return __atomic_test_and_set(p, 5); }}\n");
4676            let text = body(&source);
4677            assert!(text.contains("%1 = iconst.i8 1"), "{pointer}: {text}");
4678            assert!(
4679                text.contains("%2 = atomic_rmw.i8 xchg %0, %1, align 1, seq_cst"),
4680                "{pointer}: {text}"
4681            );
4682            assert!(text.contains("%4 = icmp ne %2, %3"), "{pointer}: {text}");
4683
4684            let source = format!("void f({pointer} *p) {{ __atomic_clear(p, 3); }}\n");
4685            let text = body(&source);
4686            assert!(text.contains("atomic_store %2 -> %0, align 1, release"), "{pointer}: {text}");
4687        }
4688
4689        // And on this machine, where the exchange carries no `lock` because one with memory locks
4690        // the bus whether it was asked to or not. Both lines are what gcc 16.2.0 writes.
4691        let text = asm("int f(int *p) { return __atomic_test_and_set(p, 5); }\n");
4692        assert!(text.contains("xchgb\t%al, (%rdi)"), "{text}");
4693        assert!(text.contains("setne\t"), "{text}");
4694    }
4695
4696    /// On this machine it is `xchg` where the machine has an exchange and `lock xadd` where it has
4697    /// an add, at the width of the object.
4698    ///
4699    /// The exchange carries no prefix and the add carries one, which is the machine rather than an
4700    /// oversight: an exchange with memory locks the bus whether it is asked to or not. Both are
4701    /// therefore full barriers whatever ordering the program wrote, so no ordering costs an
4702    /// `mfence` beside them. Every line below is what gcc 16.2.0 writes for the same function.
4703    #[test]
4704    fn a_read_modify_write_is_an_exchange_or_a_locked_add_at_the_width_of_the_object() {
4705        let widths = [("char", "b", "%sil"), ("short", "w", "%si"), ("int", "l", "%esi")];
4706        for (ty, suffix, reg) in widths {
4707            let source =
4708                format!("{ty} f({ty} *p, {ty} v) {{ return __atomic_fetch_add(p, v, 5); }}\n");
4709            let text = asm(&source);
4710            assert!(text.contains("\tlock\n"), "{ty}: {text}");
4711            assert!(text.contains(&format!("xadd{suffix}\t{reg}, (%rdi)")), "{ty}: {text}");
4712
4713            let source =
4714                format!("{ty} f({ty} *p, {ty} v) {{ return __atomic_exchange_n(p, v, 5); }}\n");
4715            let text = asm(&source);
4716            assert!(text.contains(&format!("xchg{suffix}\t{reg}, (%rdi)")), "{ty}: {text}");
4717            assert!(!text.contains("\tlock\n"), "an exchange is locked already: {ty}: {text}");
4718        }
4719        let source = "long f(long *p, long v) { return __atomic_fetch_add(p, v, 5); }\n";
4720        assert!(asm(source).contains("xaddq\t%rsi, (%rdi)"), "{}", asm(source));
4721
4722        // A subtraction is the same instruction over the negated operand, which is right at every
4723        // width because the machine's arithmetic wraps.
4724        let source = "int f(int *p, int v) { return __atomic_fetch_sub(p, v, 5); }\n";
4725        let text = asm(source);
4726        assert!(text.contains("negl\t"), "{text}");
4727        assert!(text.contains("xaddl\t"), "{text}");
4728
4729        // The ordering changes nothing, for the reason it changes nothing for a compare and
4730        // exchange: a locked instruction on this machine orders everything whatever it was asked.
4731        for order in ["0", "2", "3", "4", "5"] {
4732            let source =
4733                format!("int f(int *p, int v) {{ return __atomic_fetch_add(p, v, {order}); }}\n");
4734            let text = asm(&source);
4735            assert!(text.contains("xaddl\t"), "{order}: {text}");
4736            assert!(!text.contains("mfence"), "{order} needs no barrier here: {text}");
4737        }
4738
4739        // And the lock pair, which is the exchange and a store of a zero. Neither is a barrier
4740        // instruction: the exchange is one already and the store is a release, which this machine
4741        // gives away.
4742        let text = asm("int f(int *p, int v) { return __sync_lock_test_and_set(p, v); }\n");
4743        assert!(text.contains("xchgl\t%esi, (%rdi)"), "{text}");
4744        // The zero goes through a register on the way, which is where every constant this
4745        // compiler stores goes: gcc writes the one instruction because it has a store that takes an
4746        // immediate and no rule here does. That is a rule this rule set is missing rather than
4747        // anything about the builtin, and it is the same two instructions a plain `*p = 0` makes.
4748        let text = asm("void f(int *p) { __sync_lock_release(p); }\n");
4749        assert!(text.contains("movl\t$0, %eax"), "{text}");
4750        assert!(text.contains("movl\t%eax, (%rdi)"), "{text}");
4751        assert!(!text.contains("mfence"), "a release store needs no barrier here: {text}");
4752    }
4753
4754    /// The two lock free questions are numbers in the program rather than calls to anything.
4755    ///
4756    /// Both answer from the size, which has to be a power of two no wider than the widest access
4757    /// this compiler writes, and from what the pointer says about the alignment. Sixteen bytes is
4758    /// no here and is no in gcc without `-mcx16`, because `cmpxchg16b` is not in the baseline and
4759    /// nothing here writes it. Three bytes is no because there is no three byte access at all.
4760    ///
4761    /// The whole point of both names is that the answer is available before the program runs, so
4762    /// what is checked is that a `mov` of a constant is the whole function and that no call was
4763    /// left behind. A call would be to `__atomic_is_lock_free` in libatomic, which is not a library
4764    /// this links against.
4765    #[test]
4766    fn the_lock_free_questions_are_answered_as_constants() {
4767        for size in ["1", "2", "4", "8"] {
4768            let source =
4769                format!("int f(void) {{ return __atomic_always_lock_free({size}, 0); }}\n");
4770            let text = asm(&source);
4771            assert!(text.contains("movb\t$1, %al"), "{size} bytes is lock free: {text}");
4772            assert!(!text.contains("call"), "and is not a call: {text}");
4773        }
4774        for size in ["3", "16", "sizeof(long double)"] {
4775            let source = format!("int f(void) {{ return __atomic_is_lock_free({size}, 0); }}\n");
4776            let text = asm(&source);
4777            assert!(text.contains("movb\t$0, %al"), "{size} bytes is not: {text}");
4778            assert!(!text.contains("call"), "and is not a call either: {text}");
4779        }
4780
4781        // A size the compiler cannot work out, which is no rather than a refusal, and an object
4782        // whose type is aligned under the size asked about, which is the whole of what the second
4783        // argument is for.
4784        let text = asm("int f(int n) { return __atomic_is_lock_free(n, 0); }\n");
4785        assert!(text.contains("movb\t$0, %al"), "a size nobody knows is not lock free: {text}");
4786        let text = asm("int f(int *p) { return __atomic_always_lock_free(8, p); }\n");
4787        assert!(text.contains("movb\t$0, %al"), "eight bytes at four is not: {text}");
4788        let text = asm("int f(long *p) { return __atomic_always_lock_free(8, p); }\n");
4789        assert!(text.contains("movb\t$1, %al"), "and at eight it is: {text}");
4790    }
4791
4792    /// A memory order an operation cannot carry is read as the strongest one, and said so about.
4793    ///
4794    /// There are three ways the number is not one the operation can take: it is not a constant at
4795    /// all, it is not one of the six the headers define, or it is one of them and means nothing for
4796    /// this operation, which is a release load or an acquire store. All three become sequential
4797    /// consistency, which is stronger than anything the program could have meant, so a program that
4798    /// wrote nonsense gets a correct answer rather than a fast one. gcc does the same.
4799    ///
4800    /// The last two also warn, because the number was written down and is wrong. The first does
4801    /// not: gcc takes a computed order, and so does the C11 spelling, so a warning there would fire
4802    /// on correct programs.
4803    #[test]
4804    fn a_memory_order_an_operation_cannot_carry_is_read_as_the_strongest() {
4805        let mut opts = options();
4806        opts.emit = EmitKind::Ir;
4807
4808        let acquire_store = run(&opts, "void f(int *p, int v) { __atomic_store_n(p, v, 2); }\n");
4809        assert!(acquire_store.text().contains("seq_cst"), "{:?}", acquire_store.text());
4810        assert!(acquire_store.messages[0].contains("[W0333]"), "{:?}", acquire_store.messages);
4811
4812        let nonsense = run(&opts, "int f(int *p) { return __atomic_load_n(p, 99); }\n");
4813        assert!(nonsense.text().contains("seq_cst"), "{:?}", nonsense.text());
4814        assert!(nonsense.messages[0].contains("[W0333]"), "{:?}", nonsense.messages);
4815
4816        let computed = run(&opts, "int f(int *p, int n) { return __atomic_load_n(p, n); }\n");
4817        assert!(computed.text().contains("seq_cst"), "{:?}", computed.text());
4818        assert_eq!(computed.messages, Vec::<String>::new(), "a computed order is not a mistake");
4819    }
4820
4821    /// A conversion between a float and the widest unsigned integer, which the machine has not got.
4822    ///
4823    /// Every other conversion between a float and an integer is the signed one at some width with a
4824    /// widening in front or a narrowing behind. These two are not, because there is no signed width
4825    /// that holds every value of an unsigned sixty four bit integer, so each is the signed
4826    /// conversion with arithmetic around it that brings the value into range and puts it back.
4827    ///
4828    /// What is checked here is that the conversion happens at all and that it happens without a
4829    /// branch. gcc writes a branch for both; this writes the choice as a mask, because every rewrite
4830    /// in that pass stays inside the block it started in. The arithmetic itself is checked in
4831    /// `rucc-codegen`, where it can be run against the answer rather than read in the assembly.
4832    #[test]
4833    fn a_conversion_between_a_float_and_the_widest_unsigned_integer_is_written_without_a_branch() {
4834        let text = asm("double f(unsigned long long x) { return (double)x; }\n");
4835        assert!(text.contains("cvtsi2sdq"), "the signed conversion is what runs: {text}");
4836        assert!(text.contains("shrq"), "with the value halved first: {text}");
4837        assert!(text.contains("addsd"), "and doubled after: {text}");
4838        assert!(!text.contains("\tj"), "and no branch anywhere: {text}");
4839
4840        let text = asm("unsigned long long f(double d) { return (unsigned long long)d; }\n");
4841        assert!(text.contains("cvttsd2siq"), "the signed conversion is what runs: {text}");
4842        assert!(text.contains("subsd"), "with half the range taken off first: {text}");
4843        assert!(text.contains("shlq\t$63"), "and the top bit put back: {text}");
4844        assert!(!text.contains("\tj"), "and no branch anywhere: {text}");
4845    }
4846
4847    /// The plain names are the library's only where nothing else has taken them.
4848    ///
4849    /// Four ways a program says it means something else. A `static` definition is its own
4850    /// function and the name outside the file is somebody else's. A declaration of another type
4851    /// is another function. `-fno-builtin` and `-fno-builtin-<name>` say so outright, and
4852    /// `-ffreestanding` says there is no C library for the name to be the name of. Every one of
4853    /// these was measured against gcc 16.2.0, which calls the program's function in all of them.
4854    ///
4855    /// The `__builtin_` spelling goes on meaning the library's function through all of it, which
4856    /// is what the prefix is for and what lets a freestanding build reach one deliberately.
4857    #[test]
4858    fn a_plain_name_the_program_took_is_the_programs_own_function() {
4859        let taken = concat!(
4860            "static long long llabs(long long b) { return 7; }\n",
4861            "long long f(long long x) { return llabs(x); }\n",
4862        );
4863        assert!(ir(taken).contains("call @llabs"), "a static definition is the program's own");
4864
4865        let retyped = concat!("int llabs(int b);\n", "int f(int x) { return llabs(x); }\n",);
4866        assert!(ir(retyped).contains("call @llabs"), "another type is another function");
4867
4868        let plain = concat!(
4869            "long long llabs(long long b);\n",
4870            "long long f(long long x) { return llabs(x); }\n",
4871        );
4872        let mut opts = options();
4873        opts.emit = EmitKind::Ir;
4874        assert!(!run(&opts, plain).text().contains("call @llabs"), "the library's by default");
4875
4876        opts.builtins = false;
4877        assert!(run(&opts, plain).text().contains("call @llabs"), "-fno-builtin");
4878
4879        opts.builtins = true;
4880        opts.no_builtin = vec!["llabs".to_owned()];
4881        assert!(run(&opts, plain).text().contains("call @llabs"), "-fno-builtin-llabs");
4882        let one = "long labs(long b);\nlong f(long x) { return labs(x); }\n";
4883        assert!(!run(&opts, one).text().contains("call @labs"), "one name and not the family");
4884
4885        // `-ffreestanding` reaches the front end as the same answer, which is what the driver
4886        // does with it in `compile`, and the prefixed spelling is untouched by any of it.
4887        opts.no_builtin = Vec::new();
4888        opts.builtins = false;
4889        let prefixed = "long long f(long long x) { return __builtin_llabs(x); }\n";
4890        assert!(!run(&opts, prefixed).text().contains("call @llabs"), "the prefix is a promise");
4891    }
4892
4893    /// The hint builtins are their first argument, and nothing is left of the hint.
4894    ///
4895    /// Which way a branch is expected to go is the whole of what they say, and there is nothing
4896    /// here that reads a branch weight yet, so what reaches the IR is the value and the hint is
4897    /// gone. The one thing the prototype has to keep doing is converting: gcc gives both of them
4898    /// a `long` result, so `sizeof(__builtin_expect((char)1, 1))` is eight and a narrower argument
4899    /// widens before it is answered with.
4900    ///
4901    /// Whether a side effect in the hint happens depends on the first argument, which is gcc's
4902    /// answer rather than a rule anybody designed. A constant first argument folds the whole call
4903    /// where it is written and the hint goes with it, and a first argument that is not a constant
4904    /// leaves the hint standing. Both halves are below and both were measured on gcc 16.2.0.
4905    #[test]
4906    fn the_hint_builtins_are_their_first_argument_and_the_hint_leaves_no_trace() {
4907        let text = ir(concat!(
4908            "long a = __builtin_expect(7, 1);\n",
4909            "long b = __builtin_expect_with_probability(9, 1, 0.9);\n",
4910            "unsigned long c = sizeof(__builtin_expect((char)1, 1));\n",
4911        ));
4912        assert!(text.contains("global @a : i64 = 7,"), "{text}");
4913        assert!(text.contains("global @b : i64 = 9,"), "{text}");
4914        assert!(text.contains("global @c : i64 = 8,"), "{text}");
4915        assert!(!text.contains("__builtin_expect"), "it is not a call to anything:\n{text}");
4916
4917        // A narrower argument is widened by the prototype before it is handed back, and it is
4918        // widened with its sign, since the parameter is a signed `long`.
4919        let text = body("long f(char c) { return __builtin_expect(c, 1); }\n");
4920        assert!(text.contains("sext"), "{text}");
4921
4922        // The first argument is a constant, so the second is not evaluated and `i` is still zero,
4923        // and neither is the third. What is left of each statement is the first argument widened,
4924        // which nothing reads and which the first pass that looks for dead code will take out.
4925        let one = "block0:\n    %0 = iconst.i32 0\n    %1 = iconst.i32 1\n    %2 = sext.i64 %1\n    return %0\n";
4926        assert_eq!(body("int f(void) { int i = 0; __builtin_expect(1, i++); return i; }\n"), one);
4927        let source = "int g(void) { int i = 0; __builtin_expect_with_probability(1, i++, 0.5); return i; }\n";
4928        assert_eq!(body(source), one);
4929
4930        // The first argument is not a constant, so the hint runs and `i` comes back one. There is
4931        // an increment in the body and the value it returns is the load after it, which is what
4932        // gcc gives for the same program, and the whole of tamnd/rucc#584 is that this used to
4933        // come out the same as the pair above.
4934        let kept = body("int f(int n) { int i = 0; __builtin_expect(n, i++); return i; }\n");
4935        assert!(kept.contains("add.nsw"), "the hint still runs: {kept}");
4936        assert!(kept.ends_with("return %3\n"), "and the answer is what it left behind: {kept}");
4937        let both = "int g(int n) { int i = 0; __builtin_expect_with_probability(n, i++, 0.5); return i; }\n";
4938        assert!(body(both).contains("add.nsw"), "and so does the one with three arguments");
4939    }
4940
4941    /// A point control does not arrive at, in both of the ways the compiler has one.
4942    ///
4943    /// `__builtin_unreachable()` is the promise written down, and a function whose body can run
4944    /// off the bottom is the walk arriving at the same place on its own. Neither writes an
4945    /// instruction, which is what gcc 16.2.0 does at `-O0`: it emits the epilogue and the `ret`
4946    /// for both of the functions below and nothing else, and the two of them come out byte for
4947    /// byte the same there.
4948    ///
4949    /// The `ret` is the part worth holding on to. It is not there because anything runs it, it is
4950    /// there because a function whose last instruction is not a return is one that falls into
4951    /// whatever the assembler puts after it.
4952    #[test]
4953    fn a_promise_that_control_does_not_arrive_writes_no_instruction() {
4954        let promised = "int f(int x) { if (x) return 1; __builtin_unreachable(); }\n";
4955        let text = ir(promised);
4956        assert!(text.contains("    unreachable_hint\n"), "{text}");
4957        assert!(!text.contains("call"), "it is not a call to anything:\n{text}");
4958
4959        // The statement after it is still lowered. Continuing to translate a path the program
4960        // promised is dead is one of the things a compiler may do with undefined behaviour, and
4961        // it is the one that keeps a program built at `-O0` behaving the way it was watched to.
4962        let after = body("int g(int x) { __builtin_unreachable(); return x; }\n");
4963        assert!(after.contains("return"), "{after}");
4964
4965        // Both functions are the same instructions, because the hint writes none of them and the
4966        // terminator underneath it writes none either.
4967        let text = asm(promised);
4968        let mine = text.split_once("\nf:\n").expect("a definition").1;
4969        let mine = mine.split_once("\t.size").expect("a definition").0;
4970        let plain = asm("int f(int x) { if (x) return 1; }\n");
4971        let plain = plain.split_once("\nf:\n").expect("a definition").1;
4972        let plain = plain.split_once("\t.size").expect("a definition").0;
4973        assert_eq!(mine, plain);
4974        // The last instruction, rather than the last line, because the unwind record is closed
4975        // after it and a directive is not something the machine runs.
4976        let last = mine.lines().rfind(|line| !line.trim_start().starts_with('.'));
4977        assert_eq!(last.map(str::trim), Some("ret"), "{mine}");
4978        assert!(!mine.contains("ud2"), "{mine}");
4979    }
4980
4981    /// The two names stay apart, which is what having both of them is for.
4982    ///
4983    /// The one the program wrote is what the call is checked against and what a diagnostic about
4984    /// it says, and the one the library defines is what the call ends up carrying. A compiler
4985    /// that kept only the second would report this against `abort`, which is a function the
4986    /// program never mentions.
4987    #[test]
4988    fn a_library_builtin_is_diagnosed_under_the_name_the_program_wrote() {
4989        let mut opts = options();
4990        opts.emit = EmitKind::Ir;
4991        let messages = run(&opts, "void f(void) { __builtin_abort(1); }\n").messages;
4992        assert!(
4993            messages.iter().any(|m| m.contains("__builtin_abort")),
4994            "expected the written name in {messages:?}"
4995        );
4996    }
4997
4998    /// A builtin nothing lowers is refused where it is written, rather than at the link.
4999    ///
5000    /// One name is left, which is the last of the atomic family that is refused and is also the
5001    /// one whose prefix is not `__builtin_`; its older half has nothing left in it at all, and so
5002    /// does the half of the family that carries a prototype. What the message has to carry is the
5003    /// name, because the whole complaint about the link error this replaces is that the name in it
5004    /// was one the compiler chose.
5005    #[test]
5006    fn a_builtin_nothing_lowers_is_refused_by_name() {
5007        let mut opts = options();
5008        opts.emit = EmitKind::Ir;
5009        let builtin = "__atomic_signal_fence";
5010        let source = format!("int counter;\nint f(void) {{ return ({builtin}(5), 0); }}\n");
5011        let messages = run(&opts, &source).messages;
5012        let named = messages.iter().any(|m| m.contains(builtin) && m.contains("E0686"));
5013        assert!(named, "expected {builtin} to be refused by name in {messages:?}");
5014    }
5015
5016    /// The refusal is about a call and not about the name, so a program that defines the name
5017    /// itself gets the function it wrote.
5018    ///
5019    /// That is not the reason the refusal exists, but a definition in front of us is a definition
5020    /// and the call to it links. It works here because the name is one with no prototype and no
5021    /// meaning the front end knows, which is what is left once the rest of the family is
5022    /// implemented: a `__builtin_` name the front end does answer is answered whatever the program
5023    /// declares, the way gcc answers one.
5024    #[test]
5025    fn what_is_refused_is_the_call_and_not_the_name() {
5026        let text = ir(concat!(
5027            "void __atomic_signal_fence(int order) { (void)order; }\n",
5028            "void f(void) { __atomic_signal_fence(5); }\n",
5029        ));
5030        assert!(text.contains("call @__atomic_signal_fence"), "{text}");
5031    }
5032
5033    /// How many bytes are behind an address is read off the layout, for every shape the walk
5034    /// covers.
5035    ///
5036    /// This is what `_FORTIFY_SOURCE` runs on, so the numbers matter one at a time rather than in
5037    /// aggregate: a size too small turns a correct copy into an abort, and a size too large turns
5038    /// a checked copy back into an unchecked one. Every answer here was measured against gcc
5039    /// 16.2.0 first. They are written as initializers so that each one is a constant in the
5040    /// output and the test reads as the table it is.
5041    #[test]
5042    fn the_object_size_of_an_address_is_what_the_layout_leaves_in_front_of_it() {
5043        let text = ir(concat!(
5044            "struct S { char a[8]; int n; char b[12]; };\n",
5045            "char g[32];\n",
5046            "struct S gs;\n",
5047            "unsigned long whole = __builtin_object_size(g, 0);\n",
5048            "unsigned long moved = __builtin_object_size(g + 4, 0);\n",
5049            "unsigned long back = __builtin_object_size(g + 30 - 2, 0);\n",
5050            "unsigned long outer = __builtin_object_size(gs.a, 0);\n",
5051            "unsigned long inner = __builtin_object_size(gs.a, 1);\n",
5052            "unsigned long scalar = __builtin_object_size(&gs.n, 1);\n",
5053            "unsigned long after = __builtin_object_size(&gs.n, 0);\n",
5054            "unsigned long into = __builtin_object_size(&gs.b[2], 1);\n",
5055            "unsigned long text = __builtin_object_size(\"hello\", 0);\n",
5056            "unsigned long dyn = __builtin_dynamic_object_size(gs.b, 1);\n",
5057        ));
5058        for (name, size) in [
5059            ("whole", 32),
5060            ("moved", 28),
5061            ("back", 4),
5062            ("outer", 24),
5063            ("inner", 8),
5064            ("scalar", 4),
5065            ("after", 16),
5066            ("into", 10),
5067            ("text", 6),
5068            ("dyn", 12),
5069        ] {
5070            let said = format!("global @{name} : i64 = {size},");
5071            assert!(text.contains(&said), "expected `{said}` in:\n{text}");
5072        }
5073    }
5074
5075    /// A local is as knowable as a global, which is the whole point of asking on the way into a
5076    /// copy.
5077    ///
5078    /// A fortified header expands around the destination the caller wrote, and the destination a
5079    /// program most wants checked is the buffer on its own stack. Nothing in the answer depends on
5080    /// storage duration, unlike in a constant expression, where the address of a local is exactly
5081    /// what is not allowed.
5082    #[test]
5083    fn the_object_behind_an_address_can_be_one_with_automatic_storage() {
5084        let text = body(concat!(
5085            "struct S { char a[8]; int n; char b[12]; };\n",
5086            "unsigned long f(void) {\n",
5087            "  char loc[20];\n",
5088            "  struct S ls;\n",
5089            "  return __builtin_object_size(loc + 3, 0) + __builtin_object_size(ls.b + 2, 1);\n",
5090            "}\n",
5091        ));
5092        assert!(text.contains("iconst.i64 17"), "twenty bytes with three used: {text}");
5093        assert!(text.contains("iconst.i64 10"), "twelve bytes with two used: {text}");
5094    }
5095
5096    /// An address whose object the walk cannot see answers at whichever end of the range the kind
5097    /// asks for.
5098    ///
5099    /// The two bits are a question and the answer has to fit it. A kind wanting the largest object
5100    /// the address could be in has to name a size nothing is bigger than, and a kind wanting the
5101    /// smallest has to name a size nothing is smaller than, so the unknown answers are all ones
5102    /// and zero. That pair is what a fortified header compares against to decide whether to check
5103    /// at all, and getting either of them the wrong way round turns every unknown copy into an
5104    /// abort.
5105    #[test]
5106    fn an_address_with_no_object_in_sight_answers_at_the_end_of_the_range_its_kind_asks_for() {
5107        let text = ir(concat!(
5108            "struct T { int n; char f[]; };\n",
5109            "extern char *p;\n",
5110            "extern struct T *t;\n",
5111            "unsigned long largest = __builtin_object_size(p, 0);\n",
5112            "unsigned long nearest = __builtin_object_size(p, 1);\n",
5113            "unsigned long least = __builtin_object_size(p, 2);\n",
5114            "unsigned long tight = __builtin_object_size(p, 3);\n",
5115            "unsigned long flex = __builtin_object_size(t->f, 1);\n",
5116            "int says = __builtin_object_size(p, 0) == (unsigned long)-1;\n",
5117        ));
5118        for name in ["largest", "nearest", "flex"] {
5119            // All ones, printed as the signed rendering of the sixty four bits it is held in.
5120            // `says` is what pins the pattern itself, since it is the comparison a fortified
5121            // header writes and it folds only if every bit is set.
5122            let said = format!("global @{name} : i64 = -1,");
5123            assert!(text.contains(&said), "expected `{said}` in:\n{text}");
5124        }
5125        for name in ["least", "tight"] {
5126            let said = format!("global @{name} : i64 = 0,");
5127            assert!(text.contains(&said), "expected `{said}` in:\n{text}");
5128        }
5129        assert!(text.contains("global @says : i32 = 1,"), "{text}");
5130    }
5131
5132    /// The address is not evaluated, which is the rule `sizeof` follows and for the same reason.
5133    ///
5134    /// What the builtin reads is the shape of the expression rather than the value it would
5135    /// produce, so there is nothing to run. It matters because a fortified header writes the
5136    /// destination twice, once into the copy and once into the size, and a program whose
5137    /// destination is `*next()` would advance twice if this evaluated.
5138    #[test]
5139    fn the_address_an_object_size_is_asked_about_is_not_evaluated() {
5140        let text = body(concat!(
5141            "extern char *side(void);\n",
5142            "unsigned long f(void) { return __builtin_object_size(side(), 0); }\n",
5143        ));
5144        assert!(!text.contains("call"), "nothing is called: {text}");
5145    }
5146
5147    /// The kind has to be a constant in range, because it says which of four questions was asked.
5148    ///
5149    /// A number that is not known until the program runs decides nothing, and one outside the two
5150    /// bits names no question at all. gcc refuses both in one sentence and so does this.
5151    #[test]
5152    fn a_kind_that_is_not_one_of_the_four_is_refused() {
5153        for source in [
5154            "extern char *p;\nextern int k;\nunsigned long f(void) ".to_owned()
5155                + "{ return __builtin_object_size(p, k); }\n",
5156            "extern char *p;\nunsigned long f(void) { return __builtin_object_size(p, 4); }\n"
5157                .to_owned(),
5158            "extern char *p;\nunsigned long f(void) ".to_owned()
5159                + "{ return __builtin_dynamic_object_size(p, -1); }\n",
5160        ] {
5161            let messages = errors(&source);
5162            let named = messages.iter().any(|m| m.contains("E0709") && m.contains("0 to 3"));
5163            assert!(named, "expected a complaint about the kind in {messages:?}");
5164        }
5165    }
5166
5167    /// The pair that saves a place in a function and comes back to it, which is not a call.
5168    ///
5169    /// What the IR has to show is one instruction each and no call to anything: there is no
5170    /// function of either name for a call to reach, and a program that got one would fail to link.
5171    /// The save answers an `int`, which is the value that says how control got there.
5172    #[test]
5173    fn the_pair_that_saves_a_place_lowers_to_the_two_markers() {
5174        let text = ir(concat!(
5175            "void *buf[5];\n",
5176            "int f(void) {\n",
5177            "  if (__builtin_setjmp(buf)) return 2;\n",
5178            "  return 1;\n",
5179            "}\n",
5180            "void g(void) { __builtin_longjmp(buf, 1); }\n",
5181        ));
5182        assert!(text.contains("= setjmp_marker.i32 %0\n"), "the save answers a value: {text}");
5183        assert!(text.contains("    longjmp_marker %0\n"), "the restore answers nothing: {text}");
5184        assert!(!text.contains("call @"), "neither of them is a call: {text}");
5185    }
5186
5187    /// Every local of a function that saves a place lives in the frame, and not in a value.
5188    ///
5189    /// The edge a restore travels is not an edge of the graph, so a local the SSA construction
5190    /// renamed would answer the write that reached the read along the edges there are rather than
5191    /// the write that last ran. The second function here is the same code without the save, where
5192    /// the local is a value and there is no slot at all, which is what makes the first one a rule
5193    /// about the save and not about the shape of the code.
5194    #[test]
5195    fn a_local_of_a_function_that_saves_a_place_gets_a_slot() {
5196        let text = ir(concat!(
5197            "void *buf[5];\n",
5198            "int f(int x) { int a = 0; if (__builtin_setjmp(buf)) return a; a = 1; return x; }\n",
5199            "int g(int x) { int a = 0; if (x) return a; a = 1; return x; }\n",
5200        ));
5201        let (saves, plain) = text.split_once("func @g").expect("both functions");
5202        assert_eq!(saves.matches("= alloca").count(), 2, "the parameter and the local: {text}");
5203        assert!(saves.contains("store %9 -> %2"), "the local is written through: {text}");
5204        assert!(!plain.contains("alloca"), "nothing in the plain one needs a slot: {text}");
5205    }
5206
5207    /// What the save writes and where it leaves control, which is a new block.
5208    ///
5209    /// Four words: the frame pointer, the address to come back to, the stack pointer, and the
5210    /// address of the word the answer arrives in, which is this compiler's own and is why the
5211    /// block after the save opens with a load. The frame pointer is kept although the function
5212    /// asked for nothing and calls nothing, since the epilogue has to find the caller's frame
5213    /// after control has come back, and the frame is grown although there is one word in it,
5214    /// since a function control comes back into cannot use the red zone.
5215    #[test]
5216    fn the_save_writes_four_words_and_carries_on_in_a_new_block() {
5217        let text =
5218            asm(concat!("void *buf[5];\n", "int f(void) { return __builtin_setjmp(buf); }\n",));
5219        let body = text.split_once("\nf:\n").expect("the function").1;
5220        assert!(body.contains("\tmovq\t%rsp, %rbp\n"), "a frame pointer whatever: {text}");
5221        assert!(body.contains("\tsubq\t$8, %rsp\n"), "no red zone: {text}");
5222        assert!(body.contains("\tmovq\t%rbp, (%rax)\n"), "the frame pointer: {text}");
5223        assert!(body.contains("\tmovq\t%rsp, 16(%rax)\n"), "the stack pointer: {text}");
5224        assert!(body.contains("\tleaq\t.Lf_1(%rip), %rcx\n"), "where to come back to: {text}");
5225        assert!(body.contains("\tmovq\t%rcx, 8(%rax)\n"), "and that goes in the buffer: {text}");
5226        let back = body.split_once(".Lf_1:\n").expect("the block control comes back to").1;
5227        assert!(back.starts_with("\tmovq\t(%rsp), %rax\n"), "the answer is read back: {text}");
5228    }
5229
5230    /// Nothing stays in a register across the save, which is said with a write of every one of
5231    /// them and shows up as the callee-saved registers the function saves and restores.
5232    ///
5233    /// The restore puts back two registers and no others, so a function coming back through one
5234    /// finds every other register holding whatever the code between the two put there. The pushes
5235    /// are what makes the epilogue right on that path: the values popped are the caller's, off the
5236    /// stack the restore put back, rather than whatever is in the registers when control arrives.
5237    #[test]
5238    fn a_save_destroys_every_register_the_allocator_hands_out() {
5239        let text =
5240            asm(concat!("void *buf[5];\n", "int f(void) { return __builtin_setjmp(buf); }\n",));
5241        for reg in ["%rbx", "%r12", "%r13", "%r14", "%r15"] {
5242            assert!(text.contains(&format!("\tpushq\t{reg}\n")), "{reg} is saved: {text}");
5243            assert!(text.contains(&format!("\tpopq\t{reg}\n")), "{reg} is restored: {text}");
5244        }
5245    }
5246
5247    /// The restore puts both registers back before it goes, at every level.
5248    ///
5249    /// The jump reads the two of them as well as the address it goes through, which is what keeps
5250    /// it behind them. Without that the two instructions write registers nothing reads, and the
5251    /// scheduler at `-O2` puts the jump in front of both and the program comes back to a frame
5252    /// that is not there.
5253    #[test]
5254    fn the_restore_puts_the_frame_back_before_it_jumps() {
5255        for level in [rucc_session::OptLevel::O0, rucc_session::OptLevel::O2] {
5256            let mut opts = options();
5257            opts.emit = EmitKind::Asm;
5258            opts.opt_level = level;
5259            let source = "void *buf[5];\nvoid g(void) { __builtin_longjmp(buf, 1); }\n";
5260            let result = run(&opts, source);
5261            assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile");
5262            let text = result.text().to_owned();
5263            let jump = text.find("\tjmp\t*%").unwrap_or_else(|| panic!("an indirect jump: {text}"));
5264            let stack = text.find(", %rsp\n").unwrap_or_else(|| panic!("the stack back: {text}"));
5265            let frame = text.find(", %rbp\n").unwrap_or_else(|| panic!("the frame back: {text}"));
5266            assert!(stack < jump, "the stack goes back first at {level:?}: {text}");
5267            assert!(frame < jump, "and so does the frame at {level:?}: {text}");
5268        }
5269    }
5270
5271    /// The second argument of the restore has one allowed value, which gcc 16.2.0 also insists on.
5272    ///
5273    /// This pair does not carry a value back the way the library's `longjmp` does, because what
5274    /// the matching save answers is decided by which way control reached it. So the argument is a
5275    /// place-holder, and a program that wrote anything else meant the library's function.
5276    #[test]
5277    fn a_longjmp_whose_second_argument_is_not_one_is_turned_down() {
5278        for source in [
5279            "void *buf[5];\nvoid f(void) { __builtin_longjmp(buf, 0); }\n",
5280            "void *buf[5];\nextern int v;\nvoid f(void) { __builtin_longjmp(buf, v); }\n",
5281        ] {
5282            let messages = errors(source);
5283            let named = messages.iter().any(|m| m.contains("E0710"));
5284            assert!(named, "expected a complaint about the value in {messages:?}");
5285        }
5286    }
5287
5288    /// A `static` function nothing refers to is not emitted, and one that is refered to is.
5289    ///
5290    /// The pair is written as one program so that the two answers come out of one walk. What
5291    /// makes the difference is the call in `main` and nothing else about either definition.
5292    #[test]
5293    fn a_static_function_nothing_refers_to_is_not_emitted() {
5294        let text = ir("static int dropped(void) { return 1; }\n\
5295                       static int kept(void) { return 2; }\n\
5296                       int main(void) { return kept(); }\n");
5297        assert!(text.contains("func @kept"), "{text}");
5298        assert!(!text.contains("dropped"), "{text}");
5299    }
5300
5301    /// The set is transitive, so two of them that only call each other are both dropped.
5302    ///
5303    /// Counting the references to a name would keep this pair, since each is named once, and
5304    /// that is the mistake this is here to catch: what decides it is whether a root reaches the
5305    /// definition, and a root is something the file has a reason to emit on its own.
5306    #[test]
5307    fn two_static_functions_that_only_call_each_other_are_both_dropped() {
5308        let text = ir("static int ping(void);\n\
5309                       static int pong(void) { return ping(); }\n\
5310                       static int ping(void) { return pong(); }\n\
5311                       int main(void) { return 0; }\n");
5312        assert!(!text.contains("ping"), "{text}");
5313        assert!(!text.contains("pong"), "{text}");
5314    }
5315
5316    /// Everything that names a function keeps it, whether or not the name is being called.
5317    ///
5318    /// An address taken in a body, an image that holds one, and a body that is only reached
5319    /// through another `static` function are three different ways for a definition to be needed
5320    /// and none of them is a call at the top level of a reachable function.
5321    #[test]
5322    fn naming_a_static_function_anywhere_keeps_it() {
5323        let text = ir("static int by_address(void) { return 1; }\n\
5324                       static int in_an_image(void) { return 2; }\n\
5325                       static int deeper(void) { return 3; }\n\
5326                       static int reaches_deeper(void) { return deeper(); }\n\
5327                       static int (*table[1])(void) = {in_an_image};\n\
5328                       int main(void) {\n\
5329                         int (*p)(void) = by_address;\n\
5330                         return p() + table[0]() + reaches_deeper();\n\
5331                       }\n");
5332        for kept in ["by_address", "in_an_image", "deeper", "reaches_deeper"] {
5333            assert!(text.contains(&format!("func @{kept}")), "expected {kept} in:\n{text}");
5334        }
5335    }
5336
5337    /// An attribute that says something outside the file reaches it keeps the definition.
5338    ///
5339    /// None of the five is implemented as anything else yet, and this is the part of each of
5340    /// them that a program notices first: a symbol a linker script names or a function the
5341    /// run-up to `main` calls is not written about anywhere a C file can see.
5342    #[test]
5343    fn an_attribute_keeps_a_static_function_nothing_refers_to() {
5344        for attribute in ["used", "retain", "constructor", "destructor", "__used__"] {
5345            let source = format!(
5346                "__attribute__(({attribute})) static int kept(void) {{ return 1; }}\n\
5347                 int main(void) {{ return 0; }}\n"
5348            );
5349            let text = ir(&source);
5350            assert!(text.contains("func @kept"), "for {attribute}:\n{text}");
5351        }
5352    }
5353
5354    /// A function with external linkage is emitted whatever this file does with it, because
5355    /// another one may call it, and that is what external linkage is.
5356    #[test]
5357    fn a_function_anything_could_call_is_emitted_without_being_called() {
5358        let text =
5359            ir("int nobody_here_calls_it(void) { return 1; }\nint main(void) { return 0; }\n");
5360        assert!(text.contains("func @nobody_here_calls_it"), "{text}");
5361    }
5362
5363    /// Four of the classification builtins are operators C already has, and become those.
5364    ///
5365    /// What the standard's macro promises over the operator is that it does not raise the
5366    /// invalid operation exception on a quiet NaN. This compiler does not model floating point
5367    /// exceptions, so there is nothing left for a node of its own to carry and a second way of
5368    /// spelling a comparison would be a second thing every pass has to know about.
5369    #[test]
5370    fn a_classification_c_has_an_operator_for_is_that_operator() {
5371        for (builtin, operator) in [
5372            ("__builtin_isgreater", "binary >"),
5373            ("__builtin_isgreaterequal", "binary >="),
5374            ("__builtin_isless", "binary <"),
5375            ("__builtin_islessequal", "binary <="),
5376        ] {
5377            let source = format!("int f(double x, double y) {{ return {builtin}(x, y); }}\n");
5378            let text = tast(&source);
5379            assert!(text.contains(&format!("{operator} : int")), "for {builtin}:\n{text}");
5380        }
5381    }
5382
5383    /// The rest of the family are comparisons in the IR and never a call to anything.
5384    ///
5385    /// `math.h` defines the macro of each of these names as the builtin of the same name, so
5386    /// there is no function under any of them for a call to reach. `isunordered` and
5387    /// `islessgreater` are predicates the IR's comparison already has, `isnan` is the value that
5388    /// is unordered with itself, and the two that ask about a magnitude are written against the
5389    /// infinities. `signbit` is the one that is not a question about the value, since a negative
5390    /// zero compares equal to a positive one, so its answer comes from the bits.
5391    #[test]
5392    fn the_classification_builtins_are_comparisons_and_not_calls() {
5393        let text = body("int f(double x, double y) { return __builtin_isunordered(x, y); }\n");
5394        assert_eq!(
5395            text,
5396            "block0(%0: f64, %1: f64):\n    %2 = fcmp uno %0, %1\n    %3 = zext.i32 \
5397                          %2\n    return %3\n"
5398        );
5399
5400        // Not `x != y`, which is true when the two are unordered and so is true of a NaN.
5401        let text = body("int f(double x, double y) { return __builtin_islessgreater(x, y); }\n");
5402        assert!(text.contains("fcmp one %0, %1"), "{text}");
5403
5404        let text = body("int f(double x) { return __builtin_isnan(x); }\n");
5405        assert!(text.contains("fcmp uno %0, %0"), "{text}");
5406
5407        let text = body("int f(double x) { return __builtin_isinf(x); }\n");
5408        assert!(text.contains("fconst.f64 0x7ff0000000000000"), "{text}");
5409        assert!(text.contains("fconst.f64 0xfff0000000000000"), "{text}");
5410        assert!(text.contains("%3 = fcmp oeq %0, %1"), "{text}");
5411        assert!(text.contains("%4 = fcmp oeq %0, %2"), "{text}");
5412        assert!(text.contains("%5 = or %3, %4"), "{text}");
5413
5414        // Strictly between the two infinities, which a NaN is not, because an ordered comparison
5415        // against either of them is false. That is what makes this one test rather than two.
5416        let text = body("int f(double x) { return __builtin_isfinite(x); }\n");
5417        assert!(text.contains("%3 = fcmp olt %2, %0"), "{text}");
5418        assert!(text.contains("%4 = fcmp olt %0, %1"), "{text}");
5419        assert!(text.contains("%5 = and %3, %4"), "{text}");
5420
5421        let text = body("int f(double x) { return __builtin_signbit(x); }\n");
5422        assert!(text.contains("%1 = bitcast.i64 %0"), "{text}");
5423        assert!(text.contains("icmp slt %1, %2"), "{text}");
5424
5425        // The same question of a value in the target's widest format, where the bits are eighty
5426        // and the object they sit in is sixteen bytes.
5427        let text = body("int f(long double x) { return __builtin_signbitl(x); }\n");
5428        assert!(text.contains("%1 = bitcast.i80 %0"), "{text}");
5429
5430        // The operand is evaluated once however many times it is compared, which is the whole
5431        // reason these are nodes rather than a rewriting into the operators.
5432        let text = body("double g(void);\nint f(void) { return __builtin_isnan(g()); }\n");
5433        assert_eq!(text.matches("call @g()").count(), 1, "{text}");
5434    }
5435
5436    /// A spelling that names a width converts its argument before it asks.
5437    ///
5438    /// gcc gives `__builtin_isinff` a `float` parameter and `__builtin_isinf` no parameter type
5439    /// at all, and the difference is visible rather than academic: `1e300` does not fit in a
5440    /// `float`, so converting it first is an infinity and not converting it is not. Both numbers
5441    /// here are what gcc 16 gives.
5442    #[test]
5443    fn a_classification_spelling_that_names_a_width_converts_before_it_asks() {
5444        let text = ir(concat!(
5445            "int a = __builtin_isinff(1e300);\n",
5446            "int b = __builtin_isinf(1e300);\n",
5447            // Folded here rather than compared at run time, because a question about a value has
5448            // an answer as soon as the value is a constant, and an initializer for an object
5449            // with static storage duration has to have one.
5450            "int c = __builtin_isnan(0.0);\n",
5451            "int d = __builtin_signbit(-0.0);\n",
5452            "int e = __builtin_islessgreater(1.0, 2.0);\n",
5453        ));
5454        assert!(text.contains("global @a : i32 = 1,"), "{text}");
5455        assert!(text.contains("global @b : i32 = 0,"), "{text}");
5456        assert!(text.contains("global @c : i32 = 0,"), "{text}");
5457        assert!(text.contains("global @d : i32 = 1,"), "{text}");
5458        assert!(text.contains("global @e : i32 = 1,"), "{text}");
5459    }
5460
5461    /// An argument that is not floating point is refused, in gcc's words.
5462    #[test]
5463    fn a_classification_builtin_refuses_an_argument_that_is_not_floating_point() {
5464        let mut opts = options();
5465        opts.emit = EmitKind::Ir;
5466        let source = concat!(
5467            "int a(int x) { return __builtin_isnan(x); }\n",
5468            "int b(int x, int y) { return __builtin_isunordered(x, y); }\n",
5469            "int c(double x) { return __builtin_isnan(x, x); }\n",
5470        );
5471        let messages = run(&opts, source).messages;
5472        assert_eq!(
5473            messages,
5474            [
5475                "/main.c:1:23: error: non-floating-point argument in call to function \
5476                 '__builtin_isnan' [E0685]",
5477                "/main.c:2:30: error: non-floating-point arguments in call to function \
5478                 '__builtin_isunordered' [E0685]",
5479                "/main.c:3:26: error: too many arguments to function '__builtin_isnan' [E0511]",
5480            ]
5481        );
5482    }
5483
5484    /// The three of the family that need a constant of the format other than an infinity.
5485    ///
5486    /// `isnormal` is the one that needs the smallest normal, and it is asked of the magnitude, so
5487    /// the sign comes off first and what is left is the same shape as `isfinite`. `isinf_sign` is
5488    /// the one whose answer is a number: the two comparisons `isinf` builds, subtracted rather
5489    /// than combined. `fpclassify` is four questions of one value and five answers to pick from,
5490    /// and the picking is a mask because all five are constants and neither of them can have an
5491    /// effect.
5492    #[test]
5493    fn the_last_three_classification_builtins_are_comparisons_and_not_calls() {
5494        let text = body("int f(double x) { return __builtin_isnormal(x); }\n");
5495        // The sign off, which is the magnitude, and then the range, asked of the bits rather than
5496        // of the number, since the encoding of a value whose sign bit is clear rises with the
5497        // value in every format this compiles for.
5498        assert!(text.contains("%1 = bitcast.i64 %0"), "{text}");
5499        assert!(text.contains("%2 = iconst.i64 9223372036854775807"), "{text}");
5500        assert!(text.contains("%3 = and %1, %2"), "{text}");
5501        assert!(text.contains("%4 = iconst.i64 4503599627370496"), "{text}");
5502        assert!(text.contains("%5 = iconst.i64 9218868437227405312"), "{text}");
5503        assert!(text.contains("%6 = icmp uge %3, %4"), "{text}");
5504        assert!(text.contains("%7 = icmp ult %3, %5"), "{text}");
5505        assert!(text.contains("%8 = and %6, %7"), "{text}");
5506
5507        // The same question in the target's widest format, where the smallest normal has the
5508        // leading significand bit stored rather than implied, so its encoding is two bits and not
5509        // one.
5510        let text = body("int f(long double x) { return __builtin_isnormal(x); }\n");
5511        assert!(text.contains("%4 = iconst.i80 27670116110564327424"), "{text}");
5512        assert!(text.contains("%5 = iconst.i80 604453686435277732577280"), "{text}");
5513
5514        let text = body("int f(double x) { return __builtin_isinf_sign(x); }\n");
5515        assert!(text.contains("%3 = fcmp oeq %0, %1"), "{text}");
5516        assert!(text.contains("%4 = fcmp oeq %0, %2"), "{text}");
5517        assert!(text.contains("%7 = sub %5, %6"), "{text}");
5518
5519        let text = body("int f(double x) { return __builtin_fpclassify(0, 1, 2, 3, 4, x); }\n");
5520        assert!(text.contains("fcmp uno %0, %0"), "{text}");
5521        assert!(text.contains("fcmp oeq %0, %6"), "{text}");
5522        // Four questions, each of them a bit widened into the type of the answer and then spread
5523        // into a mask that picks between the answer and whatever the questions after it settled
5524        // on. Nothing sign extends, because no rule lowers a sign extension out of one bit.
5525        assert_eq!(text.matches(" = zext.i32 ").count(), 4, "{text}");
5526        assert_eq!(text.matches(" = xor ").count(), 4, "{text}");
5527        assert!(!text.contains("call"), "{text}");
5528
5529        // The value is evaluated once however many questions are asked of it, which is the whole
5530        // reason `fpclassify` is a node rather than the chain of tests it turns into.
5531        let text = body(concat!(
5532            "double g(void);\n",
5533            "int f(void) { return __builtin_fpclassify(0, 1, 2, 3, 4, g()); }\n",
5534        ));
5535        assert_eq!(text.matches("call @g()").count(), 1, "{text}");
5536    }
5537
5538    /// Each of the three answers a constant where its operand is one.
5539    ///
5540    /// glibc's `fpclassify` macro is exactly this builtin, so a program that writes
5541    /// `fpclassify(0.0)` in a static initializer is writing this, and it has to have a value at
5542    /// translation time or the program is refused rather than merely compiled slowly. Every
5543    /// number here is what gcc 16 gives.
5544    #[test]
5545    fn the_last_three_classification_builtins_fold_where_their_operand_is_a_constant() {
5546        let text = ir(concat!(
5547            "int a = __builtin_isnormal(1.0);\n",
5548            "int b = __builtin_isnormal(0.0);\n",
5549            "int c = __builtin_isnormal(1.0 / 0.0);\n",
5550            "int d = __builtin_isinf_sign(-1.0 / 0.0);\n",
5551            "int e = __builtin_isinf_sign(1.0);\n",
5552            "int g = __builtin_fpclassify(0, 1, 2, 3, 4, 0.0);\n",
5553            "int h = __builtin_fpclassify(0, 1, 2, 3, 4, 1.0);\n",
5554            "int i = __builtin_fpclassify(0, 1, 2, 3, 4, 1.0 / 0.0);\n",
5555        ));
5556        assert!(text.contains("global @a : i32 = 1,"), "{text}");
5557        assert!(text.contains("global @b : i32 = 0,"), "{text}");
5558        assert!(text.contains("global @c : i32 = 0,"), "{text}");
5559        assert!(text.contains("global @d : i32 = -1,"), "{text}");
5560        assert!(text.contains("global @e : i32 = 0,"), "{text}");
5561        assert!(text.contains("global @g : i32 = 4,"), "{text}");
5562        assert!(text.contains("global @h : i32 = 2,"), "{text}");
5563        assert!(text.contains("global @i : i32 = 1,"), "{text}");
5564    }
5565
5566    /// `fpclassify` refuses what gcc refuses, in gcc's words.
5567    ///
5568    /// The five answers have to be integer constant expressions, because what the builtin does is
5569    /// pick one of them and a pick between values that are not known here would be a chain of
5570    /// conditionals over expressions the call has already evaluated.
5571    #[test]
5572    fn fpclassify_refuses_an_answer_that_is_not_an_integer_constant() {
5573        let mut opts = options();
5574        opts.emit = EmitKind::Ir;
5575        let source = concat!(
5576            "int a(double x, int n) { return __builtin_fpclassify(0, 1, n, 3, 4, x); }\n",
5577            "int b(double x) { return __builtin_fpclassify(0, 1, 2, 3, x); }\n",
5578            "int c(int x) { return __builtin_fpclassify(0, 1, 2, 3, 4, x); }\n",
5579        );
5580        let messages = run(&opts, source).messages;
5581        assert_eq!(
5582            messages,
5583            [
5584                "/main.c:1:60: error: non-const integer argument 3 in call to function \
5585                 '__builtin_fpclassify' [E0687]",
5586                "/main.c:2:26: error: too few arguments to function '__builtin_fpclassify' \
5587                 [E0511]",
5588                "/main.c:3:23: error: non-floating-point argument in call to function \
5589                 '__builtin_fpclassify' [E0685]",
5590            ]
5591        );
5592    }
5593
5594    /// A builtin whose answer is a constant is one, and is not a call to the library.
5595    ///
5596    /// This is the reason the family is answered in the front end at all. `double x =
5597    /// __builtin_inf();` at file scope initializes an object with static storage duration, so
5598    /// there is no point in the program at which a call could be made, and a compiler that
5599    /// lowered it to one would reject a program gcc accepts. Every number here is the encoding
5600    /// gcc 16 gives on x86-64.
5601    #[test]
5602    fn a_builtin_whose_answer_is_a_constant_is_one_and_not_a_call() {
5603        let text = ir(concat!(
5604            "double a = __builtin_inf();\n",
5605            "float b = __builtin_huge_valf();\n",
5606            "long double c = __builtin_infl();\n",
5607            "double d = __builtin_huge_val();\n",
5608        ));
5609        assert!(text.contains("global @a : f64 = 0x7ff0000000000000,"), "{text}");
5610        assert!(text.contains("global @b : f32 = 0x7f800000,"), "{text}");
5611        assert!(text.contains("f80 0x7fff8000000000000000"), "{text}");
5612        assert!(text.contains("global @d : f64 = 0x7ff0000000000000,"), "{text}");
5613        assert!(!text.contains("call"), "{text}");
5614    }
5615
5616    /// A nan is written with the payload the program asked for.
5617    ///
5618    /// The string is read the way `strtoull` reads a number, which is what the library function
5619    /// of the same name does with it, and a string that is not one at all leaves the call for the
5620    /// library to answer at run time. A quiet nan has the high fraction bit set and a signalling
5621    /// one does not, except that a signalling nan with nothing in it would be an infinity, so it
5622    /// gets the next bit down instead. Every encoding here was measured against gcc 16, the two
5623    /// `long double` ones on a machine with the x87 format.
5624    #[test]
5625    fn a_nan_is_written_with_the_payload_the_program_asked_for() {
5626        let text = ir(concat!(
5627            "double a = __builtin_nan(\"\");\n",
5628            "double b = __builtin_nan(\"0x1\");\n",
5629            // Octal, since there is a leading zero, so this is eight and not ten.
5630            "double c = __builtin_nan(\"010\");\n",
5631            "double d = __builtin_nans(\"\");\n",
5632            "double e = __builtin_nans(\"0x1\");\n",
5633            "float f = __builtin_nanf(\"0x1\");\n",
5634            "float g = __builtin_nansf(\"\");\n",
5635            "long double h = __builtin_nansl(\"\");\n",
5636        ));
5637        assert!(text.contains("global @a : f64 = 0x7ff8000000000000,"), "{text}");
5638        assert!(text.contains("global @b : f64 = 0x7ff8000000000001,"), "{text}");
5639        assert!(text.contains("global @c : f64 = 0x7ff8000000000008,"), "{text}");
5640        assert!(text.contains("global @d : f64 = 0x7ff4000000000000,"), "{text}");
5641        assert!(text.contains("global @e : f64 = 0x7ff0000000000001,"), "{text}");
5642        assert!(text.contains("global @f : f32 = 0x7fc00001,"), "{text}");
5643        assert!(text.contains("global @g : f32 = 0x7fa00000,"), "{text}");
5644        assert!(text.contains("f80 0x7fffa000000000000000"), "{text}");
5645
5646        // A payload that is not a number, and one that is not known until run time, are both
5647        // left to the library, which is the same thing gcc emits for either of them.
5648        let text = ir(concat!(
5649            "double f(const char *p) { return __builtin_nan(p); }\n",
5650            "double g(void) { return __builtin_nans(\"1x\"); }\n",
5651        ));
5652        assert_eq!(text.matches("call @nan(").count(), 1, "{text}");
5653        assert_eq!(text.matches("call @nans(").count(), 1, "{text}");
5654    }
5655
5656    /// The length and the order of a string literal are known here.
5657    ///
5658    /// A program that asks for either of them is asking about something the translation already
5659    /// has in front of it, and folding is not only an optimization: `execute/921007-1.c` in the
5660    /// torture suite calls `__builtin_strcmp` in a file that defines its own `strcmp` with a
5661    /// different signature, so leaving the call behind is a name collision that gcc does not
5662    /// have. The comparison is over `unsigned char`, which is why the second one is negative.
5663    #[test]
5664    fn the_length_and_the_order_of_a_string_literal_are_known_here() {
5665        let text = ir(concat!(
5666            "unsigned long a = __builtin_strlen(\"hello\");\n",
5667            "unsigned long b = __builtin_strlen(\"a\\0bc\");\n",
5668            "int c = __builtin_strcmp(\"X\", \"X\\376\") < 0;\n",
5669            "int d = __builtin_strcmp(\"abc\", \"abc\");\n",
5670            "int e = __builtin_strcmp(\"abc\", \"ab\") > 0;\n",
5671        ));
5672        assert!(text.contains("global @a : i64 = 5,"), "{text}");
5673        assert!(text.contains("global @b : i64 = 1,"), "{text}");
5674        assert!(text.contains("global @c : i32 = 1,"), "{text}");
5675        assert!(text.contains("global @d : i32 = 0,"), "{text}");
5676        assert!(text.contains("global @e : i32 = 1,"), "{text}");
5677        assert!(!text.contains("call"), "{text}");
5678
5679        // An argument that is not a literal is the library's to answer, as it has to be.
5680        let text = ir("unsigned long f(const char *p) { return __builtin_strlen(p); }\n");
5681        assert!(text.contains("call @strlen("), "{text}");
5682    }
5683
5684    /// A sign builtin is a mask over the bits, and is not a call.
5685    ///
5686    /// `fabs` and `copysign` are in the math library rather than the C one, so a program that
5687    /// only ever wrote the prefixed spelling never asked for `-lm` and a call left behind here
5688    /// would not link. Neither needs anything the library has: one clears the sign bit and the
5689    /// other takes it from the second operand, and every other bit goes through untouched.
5690    #[test]
5691    fn a_sign_builtin_is_a_mask_over_the_bits_and_not_a_call() {
5692        let text = body("double f(double x) { return __builtin_fabs(x); }\n");
5693        assert!(text.contains("bitcast.i64 %0"), "{text}");
5694        assert!(text.contains("iconst.i64 9223372036854775807"), "{text}");
5695        assert!(text.contains("and %1, %2"), "{text}");
5696        assert!(text.contains("bitcast.f64 %3"), "{text}");
5697        assert!(!text.contains("call"), "{text}");
5698
5699        let text = body("double f(double x, double y) { return __builtin_copysign(x, y); }\n");
5700        assert!(text.contains("iconst.i64 -9223372036854775808"), "{text}");
5701        assert!(text.contains("%8 = or %4, %7"), "{text}");
5702        assert!(!text.contains("call"), "{text}");
5703
5704        // The x87 format, whose value is eighty bits sitting in an object of sixteen. The mask is
5705        // as wide as the value and not as wide as the object, so the padding is not part of it.
5706        let text = body("long double f(long double x) { return __builtin_fabsl(x); }\n");
5707        assert!(text.contains("bitcast.i80 %0"), "{text}");
5708        assert!(text.contains("bitcast.f80"), "{text}");
5709
5710        // The width a name does not spell out is `double`, so a `float` argument widens first and
5711        // the answer is a `double`, which is what gcc's declaration of it says.
5712        let text = body("double f(float x) { return __builtin_fabs(x); }\n");
5713        assert!(text.contains("fpext.f64 %0"), "{text}");
5714        assert!(text.contains("bitcast.i64 %1"), "{text}");
5715    }
5716
5717    /// The plain math library names are the same mask, which is what makes a program link.
5718    ///
5719    /// `math.h` declares `fabs` and never spells `__builtin_fabs`, so the plain name is the one
5720    /// every program that includes the header reaches. Recognising only the prefixed spelling
5721    /// leaves a call to the math library behind, and the math library is not on the link line
5722    /// unless the program asked for `-lm`. parson is the project that shows it: its makefile has
5723    /// no `-lm`, it does not need one under gcc, and `undefined reference to 'fabs'` is where the
5724    /// build stopped. That is issue 630.
5725    #[test]
5726    fn the_plain_math_names_are_the_same_mask_and_not_a_call() {
5727        let text =
5728            body(concat!("double fabs(double x);\n", "double f(double x) { return fabs(x); }\n",));
5729        assert!(text.contains("iconst.i64 9223372036854775807"), "{text}");
5730        assert!(!text.contains("call"), "{text}");
5731
5732        let text =
5733            body(concat!("float fabsf(float x);\n", "float f(float x) { return fabsf(x); }\n",));
5734        assert!(text.contains("bitcast.i32 %0"), "{text}");
5735        assert!(!text.contains("call"), "{text}");
5736
5737        let text = body(concat!(
5738            "double copysign(double x, double y);\n",
5739            "double f(double x, double y) { return copysign(x, y); }\n",
5740        ));
5741        assert!(text.contains("iconst.i64 -9223372036854775808"), "{text}");
5742        assert!(!text.contains("call"), "{text}");
5743
5744        let text = body(concat!(
5745            "float copysignf(float x, float y);\n",
5746            "float f(float x, float y) { return copysignf(x, y); }\n",
5747        ));
5748        assert!(!text.contains("call"), "{text}");
5749
5750        // The `long double` pair is left alone on purpose. The prefixed spelling of both stops in
5751        // the back end with `no rule lowers a bitcast producing an i80`, so expanding the plain
5752        // name would trade a link error for a worse one. They go in with issue 540.
5753        let text = ir(concat!(
5754            "long double fabsl(long double x);\n",
5755            "long double f(long double x) { return fabsl(x); }\n",
5756        ));
5757        assert!(text.contains("call @fabsl"), "{text}");
5758    }
5759
5760    /// A plain math name the program took is the program's own function.
5761    ///
5762    /// The same four ways as the absolute value family next door, asked again here because these
5763    /// two go through a different path: the plain names of this family are taken after the call
5764    /// has been checked against the declaration, and the declaration is the whole reason the
5765    /// question can be answered at all. Measured against gcc 16.2.0, which calls the program's
5766    /// function in every one of them.
5767    #[test]
5768    fn a_plain_math_name_the_program_took_is_the_programs_own_function() {
5769        let taken = concat!(
5770            "static double fabs(double b) { return 7; }\n",
5771            "double f(double x) { return fabs(x); }\n",
5772        );
5773        assert!(ir(taken).contains("call @fabs"), "a static definition is the program's own");
5774
5775        let retyped = concat!("int fabs(int b);\n", "int f(int x) { return fabs(x); }\n");
5776        assert!(ir(retyped).contains("call @fabs"), "another type is another function");
5777
5778        let plain = concat!("double fabs(double b);\n", "double f(double x) { return fabs(x); }\n");
5779        let mut opts = options();
5780        opts.emit = EmitKind::Ir;
5781        assert!(!run(&opts, plain).text().contains("call @fabs"), "the library's by default");
5782
5783        opts.builtins = false;
5784        assert!(run(&opts, plain).text().contains("call @fabs"), "-fno-builtin");
5785
5786        opts.builtins = true;
5787        opts.no_builtin = vec!["fabs".to_owned()];
5788        assert!(run(&opts, plain).text().contains("call @fabs"), "-fno-builtin-fabs");
5789        let one = concat!(
5790            "double copysign(double a, double b);\n",
5791            "double f(double x) { return copysign(x, 1.0); }\n",
5792        );
5793        assert!(!run(&opts, one).text().contains("call @copysign"), "one name and not the family");
5794
5795        // The prefixed spelling is untouched by any of it, which is what the prefix is for.
5796        opts.no_builtin = Vec::new();
5797        opts.builtins = false;
5798        let prefixed = "double f(double x) { return __builtin_fabs(x); }\n";
5799        assert!(!run(&opts, prefixed).text().contains("call @fabs"), "the prefix is not a library");
5800    }
5801
5802    /// The sign builtins answer a zero and a nan the way the bits say.
5803    ///
5804    /// This is why they are described over the bits rather than written with comparisons and
5805    /// negation. A negative zero compares equal to a positive one and has a sign bit to clear,
5806    /// and a nan compares equal to nothing at all and keeps its payload through both operations.
5807    /// `execute/ieee/copysign1.c` in the torture suite is the test that notices, because it
5808    /// compares its answers with `memcmp`. Every number here is what gcc 16 gives, the two in the
5809    /// x87 format measured on a machine that has it.
5810    #[test]
5811    fn the_sign_builtins_answer_a_zero_and_a_nan_the_way_the_bits_say() {
5812        let text = ir(concat!(
5813            "double a = __builtin_fabs(-3.5);\n",
5814            "double b = __builtin_copysign(1.0, -0.0);\n",
5815            "double c = __builtin_copysign(0.0, -2.0);\n",
5816            // The payload survives both, and only the sign bit moves.
5817            "double d = __builtin_copysign(-__builtin_nan(\"\"), 1.0);\n",
5818            "double e = __builtin_fabs(-__builtin_nan(\"0x1\"));\n",
5819            "float g = __builtin_copysignf(-0.0f, 2.0f);\n",
5820            "long double h = __builtin_copysignl(1.0L, -1.0L);\n",
5821            "long double i = __builtin_fabsl(-__builtin_infl());\n",
5822        ));
5823        assert!(text.contains("global @a : f64 = 0x400c000000000000,"), "{text}");
5824        assert!(text.contains("global @b : f64 = 0xbff0000000000000,"), "{text}");
5825        assert!(text.contains("global @c : f64 = 0x8000000000000000,"), "{text}");
5826        assert!(text.contains("global @d : f64 = 0x7ff8000000000000,"), "{text}");
5827        assert!(text.contains("global @e : f64 = 0x7ff8000000000001,"), "{text}");
5828        assert!(text.contains("global @g : f32 = 0x0,"), "{text}");
5829        assert!(text.contains("f80 0xbfff8000000000000000"), "{text}");
5830        assert!(text.contains("f80 0x7fff8000000000000000"), "{text}");
5831    }
5832
5833    /// The complex builtins are the halves of the value, and are not a call.
5834    ///
5835    /// `conj`, `creal` and `cimag` are `~`, `__real__` and `__imag__` under the names `complex.h`
5836    /// gives them, so there is nothing for the math library to do that the translation cannot do
5837    /// with the object in front of it. Leaving the call behind would not link either, since all
5838    /// three are in the math library and a program that wrote one never had a reason to ask for
5839    /// `-lm`. Measured against gcc 16.2.0, which emits no call for any of them even at `-O0`.
5840    #[test]
5841    fn the_complex_builtins_are_the_halves_of_the_value_and_not_a_call() {
5842        let text = body("double f(_Complex double z) { return __builtin_creal(z); }\n");
5843        assert!(!text.contains("call"), "{text}");
5844        let text = body("double f(_Complex double z) { return __builtin_cimag(z); }\n");
5845        assert!(!text.contains("call"), "{text}");
5846
5847        // The conjugate is the imaginary half negated and the real half as it stands, so there is
5848        // one negation in it. A complex negation is the one with two.
5849        let text = body("_Complex double f(_Complex double z) { return __builtin_conj(z); }\n");
5850        assert_eq!(text.matches("fneg").count(), 1, "{text}");
5851        assert!(!text.contains("call"), "{text}");
5852        let negated = body("_Complex double f(_Complex double z) { return -z; }\n");
5853        assert_eq!(negated.matches("fneg").count(), 2, "{negated}");
5854
5855        // `~` on a complex operand is the same operator, which is the spelling the language has
5856        // had all along and the one a program that never included the header writes.
5857        let written = body("_Complex double f(_Complex double z) { return ~z; }\n");
5858        assert_eq!(written, text, "the name and the operator are the same thing");
5859
5860        // The plain names, which are the ones the header declares and so the ones programs write.
5861        let text = body(concat!(
5862            "double creal(_Complex double z);\n",
5863            "double f(_Complex double z) { return creal(z); }\n",
5864        ));
5865        assert!(!text.contains("call"), "{text}");
5866        let text = body(concat!(
5867            "_Complex float conjf(_Complex float z);\n",
5868            "_Complex float f(_Complex float z) { return conjf(z); }\n",
5869        ));
5870        assert_eq!(text.matches("fneg").count(), 1, "{text}");
5871        assert!(!text.contains("call"), "{text}");
5872
5873        // A program that took the name means its own function, the same four ways the absolute
5874        // value family next door asks it.
5875        let taken = concat!(
5876            "static double creal(_Complex double z) { return 7; }\n",
5877            "double f(_Complex double z) { return creal(z); }\n",
5878        );
5879        assert!(ir(taken).contains("call @creal"), "a static definition is the program's own");
5880        let retyped = concat!("int cimag(int z);\n", "int f(int z) { return cimag(z); }\n");
5881        assert!(ir(retyped).contains("call @cimag"), "another type is another function");
5882        let plain = concat!(
5883            "double cimag(_Complex double z);\n",
5884            "double f(_Complex double z) { return cimag(z); }\n",
5885        );
5886        let mut opts = options();
5887        opts.emit = EmitKind::Ir;
5888        opts.builtins = false;
5889        assert!(run(&opts, plain).text().contains("call @cimag"), "-fno-builtin");
5890        opts.builtins = true;
5891        opts.no_builtin = vec!["cimag".to_owned()];
5892        assert!(run(&opts, plain).text().contains("call @cimag"), "-fno-builtin-cimag");
5893
5894        // A constant folds, which is what a static initializer written with one needs.
5895        let text = ir(concat!(
5896            "double a = __builtin_creal(1.5 + 2.5i);\n",
5897            "double b = __builtin_cimag(1.5 + 2.5i);\n",
5898            "_Complex double c = __builtin_conj(1.5 + 2.5i);\n",
5899        ));
5900        assert!(text.contains("global @a : f64 = 0x3ff8000000000000,"), "{text}");
5901        assert!(text.contains("global @b : f64 = 0x4004000000000000,"), "{text}");
5902        assert!(
5903            text.contains("{ f64 0x3ff8000000000000, f64 0xc004000000000000 }"),
5904            "the conjugate of a constant is the constant with the second half negated: {text}"
5905        );
5906        assert!(!text.contains("call"), "{text}");
5907    }
5908
5909    /// A math library builtin handed a constant is the answer, and is not a call.
5910    ///
5911    /// This is the reason the family is answered in the front end at all. `double x =
5912    /// __builtin_ceil(1.5);` at file scope initializes an object with static storage duration, so
5913    /// there is no point in the program at which a call could be made, and a compiler that lowered
5914    /// it to one would refuse a program gcc accepts. Every number here is the encoding gcc 16.2.0
5915    /// gives on x86-64, read out of the object file one initializer at a time.
5916    #[test]
5917    fn a_math_library_builtin_of_a_constant_is_the_answer_and_not_a_call() {
5918        let text = ir(concat!(
5919            "double a = __builtin_ceil(1.5);\n",
5920            "double b = __builtin_floor(1.5);\n",
5921            "double c = __builtin_trunc(-1.5);\n",
5922            // A half goes away from zero and not to even, which is where C and the default
5923            // rounding of IEEE 754 part company.
5924            "double d = __builtin_round(2.5);\n",
5925            // The sign survives a number that rounds away to nothing, so this is a negative zero.
5926            "double e = __builtin_ceil(-0.5);\n",
5927            "double f = __builtin_fmax(1.0, 2.0);\n",
5928            "double g = __builtin_fmin(1.0, 2.0);\n",
5929            "float h = __builtin_ceilf(1.25f);\n",
5930            // The plain name is the same answer, which is what a program that included `math.h`
5931            // and never wrote a prefix reaches.
5932            "double ceil(double x);\n",
5933            "double i = ceil(2.25);\n",
5934        ));
5935        assert!(text.contains("global @a : f64 = 0x4000000000000000,"), "{text}");
5936        assert!(text.contains("global @b : f64 = 0x3ff0000000000000,"), "{text}");
5937        assert!(text.contains("global @c : f64 = 0xbff0000000000000,"), "{text}");
5938        assert!(text.contains("global @d : f64 = 0x4008000000000000,"), "{text}");
5939        assert!(text.contains("global @e : f64 = 0x8000000000000000,"), "{text}");
5940        assert!(text.contains("global @f : f64 = 0x4000000000000000,"), "{text}");
5941        assert!(text.contains("global @g : f64 = 0x3ff0000000000000,"), "{text}");
5942        assert!(text.contains("global @h : f32 = 0x40000000,"), "{text}");
5943        assert!(text.contains("global @i : f64 = 0x4008000000000000,"), "{text}");
5944        assert!(!text.contains("call"), "{text}");
5945    }
5946
5947    /// A math library builtin handed anything else is a call to the library function it is.
5948    ///
5949    /// gcc emits `jmp ceil` for `__builtin_ceil` on x86-64 at the default architecture, measured
5950    /// on gcc 16.2.0, and reaches the `roundsd` instruction only under `-msse4.1`. So the call is
5951    /// what a program gets from gcc too, and the name on it is the plain one, which is the whole
5952    /// point of the prefixed spelling: a program writing it reaches the library's function even
5953    /// where a macro or a definition of its own has taken the short name.
5954    #[test]
5955    fn a_math_library_builtin_of_anything_else_is_a_call_to_the_library() {
5956        let text = ir(concat!(
5957            "double f(double x) { return __builtin_ceil(x); }\n",
5958            "float g(float x) { return __builtin_floorf(x); }\n",
5959            "double h(double x, double y) { return __builtin_fmax(x, y); }\n",
5960        ));
5961        assert!(text.contains("call @ceil("), "{text}");
5962        assert!(text.contains("call @floorf("), "{text}");
5963        assert!(text.contains("call @fmax("), "{text}");
5964
5965        // The two the rounding mode decides are calls even when the argument is a constant, since
5966        // what they answer is not known until the program runs. gcc refuses a static initializer
5967        // written with one for that reason, so there is nothing to fold here either.
5968        let text = ir(concat!(
5969            "double f(void) { return __builtin_rint(2.5); }\n",
5970            "double g(void) { return __builtin_nearbyint(2.5); }\n",
5971        ));
5972        assert!(text.contains("call @rint("), "{text}");
5973        assert!(text.contains("call @nearbyint("), "{text}");
5974
5975        // A nan operand is the library's rule rather than the machine's, 7.12.12.2 saying the
5976        // answer is the other operand, and gcc will not fold that one either.
5977        let text = ir("double f(void) { return __builtin_fmin(__builtin_nan(\"\"), 1.0); }\n");
5978        assert!(text.contains("call @fmin("), "{text}");
5979
5980        // `-fno-builtin-ceil` is a program saying it means its own `ceil`, and it leaves the
5981        // prefixed spelling alone, which is what writing the prefix is for.
5982        let plain = concat!("double ceil(double x);\n", "double f(void) { return ceil(2.25); }\n");
5983        let mut opts = options();
5984        opts.emit = EmitKind::Ir;
5985        opts.no_builtin = vec!["ceil".to_owned()];
5986        assert!(run(&opts, plain).text().contains("call @ceil("), "-fno-builtin-ceil");
5987    }
5988
5989    /// A `constexpr` object is a named constant, which is the whole reason the keyword exists.
5990    ///
5991    /// C23 6.6p8 puts two of them on the list an integer constant expression is built from: one
5992    /// of an arithmetic type, and a member of one of a structure or union type. A subscript of
5993    /// one is not on the list and is a variably modified type in gcc 16 as well, and every
5994    /// number here is what gcc 16 gives on x86-64.
5995    #[test]
5996    fn a_constexpr_object_is_a_constant_wherever_one_is_required() {
5997        let text = ir(concat!(
5998            "constexpr int side = 4;\n",
5999            "constexpr int wider = side + 1;\n",
6000            "constexpr double half = 1.5;\n",
6001            "struct point { int x; int y; };\n",
6002            "constexpr struct point origin = { 5, 6 };\n",
6003            "int square[side * side];\n",
6004            "int rectangle[wider];\n",
6005            "int rounded[(int)half * 2];\n",
6006            "int across[origin.y];\n",
6007            "enum named { four = side };\n",
6008            "int e = four;\n",
6009        ));
6010        assert!(text.contains("global @square : bytes 64 ="), "{text}");
6011        assert!(text.contains("global @rectangle : bytes 20 ="), "{text}");
6012        assert!(text.contains("global @rounded : bytes 8 ="), "{text}");
6013        assert!(text.contains("global @across : bytes 24 ="), "{text}");
6014        assert!(text.contains("global @e : i32 = 4,"), "{text}");
6015
6016        // A `const` object is not one of them, which is what makes `int a[n];` a variable
6017        // length array in C and is the distinction the keyword was added to draw.
6018        let mut opts = options();
6019        opts.emit = EmitKind::Ir;
6020        let konst = "const int n = 1;\nint a[n];\n";
6021        let message = "/main.c:2:5: error: variably modified 'a' at file scope [E0538]";
6022        assert_eq!(run(&opts, konst).messages, [message]);
6023
6024        // Nor is a subscript of one, which gcc 16 refuses in the same words.
6025        let subscript = "constexpr int t[3] = { 1, 2, 3 };\nint a[t[1]];\n";
6026        assert_eq!(run(&opts, subscript).messages, [message]);
6027
6028        // And `constexpr` implies `const`, so the address of one is an address of a `const`.
6029        let address = "constexpr int c = 3;\nint *p = &c;\n";
6030        let warning = "/main.c:2:6: warning: initialization discards 'const' qualifier from \
6031             pointer target type [E0514]";
6032        assert_eq!(run(&opts, address).messages, [warning]);
6033    }
6034
6035    /// A definition that names its parameters and then declares them under the list.
6036    ///
6037    /// The declarations say what the types are, 6.9.1p6, and what the function takes is those
6038    /// types with the default argument promotions over them, which is what a caller of an
6039    /// unprototyped function hands over. A prototype already in scope overrules the promoted
6040    /// types, since a header saying `int narrow(char);` over a definition written this way is
6041    /// the pairing all the code written this way relies on and 6.7.6.3p15 is read that way by
6042    /// every compiler.
6043    #[test]
6044    fn an_old_style_definition_takes_its_types_from_the_declarations_under_its_list() {
6045        // C17, since the default dialect is the one that warns about the form and this is
6046        // about what it means rather than about the warning.
6047        let mut opts = options();
6048        opts.std = Std::C17;
6049        let source = concat!(
6050            "int add(a, b)\n",
6051            "int a;\n",
6052            "int b;\n",
6053            "{ return a + b; }\n",
6054            "int promoted(c)\n",
6055            "char c;\n",
6056            "{ return c; }\n",
6057            "int narrow(char);\n",
6058            "int narrow(c)\n",
6059            "char c;\n",
6060            "{ return c; }\n",
6061            "int first(a)\n",
6062            "int a[4];\n",
6063            "{ return a[0]; }\n",
6064        );
6065        let result = run(&opts, source);
6066        assert_eq!(result.messages, Vec::<String>::new(), "expected this to compile:\n{source}");
6067        let text = result.text();
6068        assert!(text.contains("add : int(int, int) function external defined"), "{text}");
6069        assert!(text.contains("promoted : int(int) function external defined"), "{text}");
6070        // The body still sees the `char` it was declared as, whatever the caller hands over.
6071        assert!(text.contains("c : char object automatic defined"), "{text}");
6072        assert!(text.contains("narrow : int(char) function external defined"), "{text}");
6073        // An array parameter is a pointer here as much as it is in a prototype.
6074        assert!(text.contains("first : int(int *) function external defined"), "{text}");
6075    }
6076
6077    /// What the two halves of an old-style parameter list can disagree about.
6078    ///
6079    /// Each of these is a sentence gcc 16 has, and every message below is the one it prints,
6080    /// read off it on x86-64 rather than reasoned about. The last two are the dialect: a name
6081    /// with no declaration is an `int` in C89 and a diagnostic from C99 on, and the whole form
6082    /// left the language in C23, where gcc still takes it and warns.
6083    #[test]
6084    fn the_two_halves_of_an_old_style_parameter_list_have_to_agree() {
6085        let mut opts = options();
6086        opts.std = Std::C17;
6087        for (source, message) in [
6088            ("int f(a, a)\nint a;\n{ return a; }\n", "1:10: error: multiple parameters named 'a'"),
6089            (
6090                "int f(a)\nint a;\nint b;\n{ return a; }\n",
6091                "3:5: error: declaration for parameter 'b' but no such parameter",
6092            ),
6093            ("int f(a)\nint a;\nint a;\n{ return a; }\n", "3:5: error: redefinition of parameter"),
6094            ("int f(a)\nint a = 1;\n{ return a; }\n", "2:5: error: parameter 'a' is initialized"),
6095            (
6096                "int f(a)\nstatic int a;\n{ return a; }\n",
6097                "2:12: error: storage class specified for parameter 'a'",
6098            ),
6099            (
6100                "int f(char);\nint f(a)\nshort a;\n{ return a; }\n",
6101                "2:7: error: argument 'a' doesn't match prototype",
6102            ),
6103        ] {
6104            let result = run(&opts, source);
6105            assert!(result.failed(), "expected this to fail:\n{source}");
6106            assert!(result.messages[0].contains(message), "{:?}", result.messages);
6107        }
6108
6109        // A name the declarations never mention. C89 gave it an `int` and gcc still takes it
6110        // in that dialect, and every dialect after it made the same line a diagnostic.
6111        let implicit = "int f(a, b)\nint a;\n{ return a + b; }\n";
6112        let mut older = options();
6113        older.std = Std::C89;
6114        assert!(!run(&older, implicit).failed(), "{:?}", run(&older, implicit).messages);
6115        let result = run(&opts, implicit);
6116        assert!(
6117            result.messages[0].contains("1:10: error: type of 'b' defaults to 'int'"),
6118            "{:?}",
6119            result.messages
6120        );
6121
6122        // C23 took the form out of the language and gcc kept accepting it with a warning, and
6123        // a warning is what this is, because the code written this way is not going to be
6124        // rewritten and refusing it would put the compiler out of reach of it.
6125        let mut newer = options();
6126        newer.std = Std::C23;
6127        let plain = "int f(a)\nint a;\n{ return a; }\n";
6128        let result = run(&newer, plain);
6129        assert!(!result.failed(), "{:?}", result.messages);
6130        assert_eq!(
6131            result.messages,
6132            ["/main.c:1:5: warning: old-style function definition [E0412]"]
6133        );
6134        assert!(run(&opts, plain).messages.is_empty(), "and nothing to say in the dialects before");
6135    }
6136
6137    /// The two obsolete designators, which are silent until `-pedantic` asks about them.
6138    ///
6139    /// `[3] 7` is what GCC had for an array before C99 settled on `[3] = 7`, and `x: 7` is the
6140    /// same era's spelling for a member. Both are still in code written against a compiler of
6141    /// that era, and gcc 16 takes both without a word unless it is asked to be pedantic, which
6142    /// is where the columns below come from as well.
6143    #[test]
6144    fn the_obsolete_designators_are_taken_and_are_pedantic_warnings() {
6145        let array = "int a[8] = { [3] 7 };\n";
6146        let member = "struct s { int x; } v = { x: 7 };\n";
6147        for source in [array, member] {
6148            let result = run(&options(), source);
6149            assert!(!result.failed(), "{:?}", result.messages);
6150            assert!(result.messages.is_empty(), "nothing to say: {:?}", result.messages);
6151        }
6152
6153        let mut asked = options();
6154        asked.pedantic = true;
6155        assert_eq!(
6156            run(&asked, array).messages,
6157            ["/main.c:1:18: warning: obsolete designator, write `[i] =` instead [E0415]"]
6158        );
6159        assert_eq!(
6160            run(&asked, member).messages,
6161            ["/main.c:1:27: warning: obsolete designator, write `.field =` instead [E0413]"]
6162        );
6163    }
6164
6165    /// A type nothing is ever an object of is a type `sizeof` still has to answer about, which
6166    /// is what `991014-1.c` in the gcc.c-torture execution suite asks.
6167    ///
6168    /// The limit is `PTRDIFF_MAX` and it is the same one for an array and for a record, so a
6169    /// record of every byte an object may have is laid out and one byte more is refused. All
6170    /// four numbers are what gcc 16 gives on x86-64.
6171    #[test]
6172    fn a_type_is_refused_when_it_passes_the_largest_object_and_not_before() {
6173        let text = ir(concat!(
6174            "struct huge_struct { short buf[(1L << 62) - 256]; int a, b, c, d; };\n",
6175            "struct brim { char buf[9223372036854775807L]; };\n",
6176            "struct bitty { char buf[9223372036854775800L]; int x : 1; };\n",
6177            "unsigned long h = sizeof(struct huge_struct);\n",
6178            "unsigned long b = sizeof(struct brim);\n",
6179            "unsigned long y = sizeof(struct bitty);\n",
6180        ));
6181        assert!(text.contains("global @h : i64 = 9223372036854775312,"), "{text}");
6182        assert!(text.contains("global @b : i64 = 9223372036854775807,"), "{text}");
6183        assert!(text.contains("global @y : i64 = 9223372036854775804,"), "{text}");
6184
6185        let mut opts = options();
6186        opts.emit = EmitKind::Ir;
6187        let over = "struct over { char buf[9223372036854775800L]; char x[8]; };\n";
6188        let message = "/main.c:1:1: error: type 'struct over' is too large [E0560]";
6189        assert_eq!(run(&opts, over).messages, [message]);
6190        let array = "struct wide { short buf[1L << 62]; };\n";
6191        let message = "/main.c:1:25: error: size of array 'buf' exceeds \
6192             maximum object size '9223372036854775807' [E0537]";
6193        assert_eq!(run(&opts, array).messages[0], message);
6194    }
6195
6196    /// A byte in the source that is not part of a character, which only a literal may hold.
6197    ///
6198    /// The source cannot be a `&str` here, which is the whole point: a file is bytes and only
6199    /// mostly text.
6200    fn compile_bytes(source: &[u8]) -> Compiled {
6201        let mut opts = options();
6202        opts.emit = EmitKind::Ir;
6203        let mut fs = MemoryFileSystem::new();
6204        fs.insert("/main.c", source.to_vec());
6205        compile(&opts, "/main.c", &fs)
6206    }
6207
6208    /// A raw byte inside a string literal is that byte, which gcc has always taken and which is
6209    /// the only place in a source file where a byte does not have to be part of a character.
6210    /// Replacing it would give the object three bytes rather than one, since the replacement
6211    /// character is three bytes of UTF-8, so the object would not be the one that was written
6212    /// even where the diagnostic is ignored. Anywhere else the byte is still a mistake, which
6213    /// is where gcc draws the same line.
6214    #[test]
6215    fn a_byte_that_is_not_a_character_is_kept_in_a_literal_and_refused_outside_one() {
6216        let mut source = b"char s[] = \"a".to_vec();
6217        source.push(0xff);
6218        source.extend_from_slice(b"b\";\nchar c = '");
6219        source.push(0xff);
6220        source.extend_from_slice(b"';\n");
6221        let result = compile_bytes(&source);
6222        assert_eq!(result.messages, Vec::<String>::new(), "a raw byte in a literal is that byte");
6223        assert!(result.text().contains(r#"bytes "a\ffb\00""#), "{}", result.text());
6224        // Plain `char` is signed on this target, so the constant is minus one rather than 255.
6225        assert!(result.text().contains("global @c : i8 = -1,"), "{}", result.text());
6226
6227        let mut stray = b"int a".to_vec();
6228        stray.push(0xff);
6229        stray.extend_from_slice(b" = 1;\n");
6230        let result = compile_bytes(&stray);
6231        assert!(
6232            result.messages.iter().any(|m| m.contains("source is not valid UTF-8 here")),
6233            "{:?}",
6234            result.messages
6235        );
6236    }
6237
6238    #[test]
6239    fn an_object_becomes_a_global_with_an_image_and_a_function_becomes_a_func() {
6240        let text = ir("int x = 7;\nint add(int a, int b) { return a + b; }\n");
6241        assert!(text.contains("global @x : i32 = 7, align 4, linkage(external)\n"), "{text}");
6242        let expected = "\
6243func @add(i32, i32) -> i32, linkage(external) {
6244block0(%0: i32, %1: i32):
6245    %2 = add.nsw %0, %1
6246    return %2
6247}
6248";
6249        assert!(text.contains(expected), "{text}");
6250    }
6251
6252    #[test]
6253    fn a_local_nothing_takes_the_address_of_is_a_value_and_never_a_stack_slot() {
6254        let text = body("int f(int n) { int a = n + 1; int b = a * 2; return a + b; }\n");
6255        assert!(!text.contains("alloca"), "{text}");
6256        assert!(!text.contains("load"), "{text}");
6257        assert!(!text.contains("store"), "{text}");
6258    }
6259
6260    #[test]
6261    fn a_local_whose_address_is_taken_gets_a_slot_in_the_entry_block() {
6262        let text = body("int g(int *);\nint f(void) { int a = 1; return g(&a); }\n");
6263        let expected = "\
6264block0:
6265    %0 = alloca, size 4, align 4
6266    %1 = iconst.i32 1
6267    store %1 -> %0, align 4, tbaa !1
6268    %2 = call @g(%0) : (ptr) -> i32
6269    return %2
6270";
6271        assert_eq!(text, expected);
6272    }
6273
6274    #[test]
6275    fn a_loop_carries_what_it_changes_as_block_parameters() {
6276        // The whole point of building SSA during the walk rather than after it: `i` and
6277        // `total` are values that arrive on an edge, and neither has ever been in memory.
6278        let text = body(
6279            "int f(int n) {\n  int total = 0;\n  for (int i = 0; i < n; i++) total += i;\n  \
6280             return total;\n}\n",
6281        );
6282        assert!(!text.contains("alloca"), "{text}");
6283        assert!(text.contains("block1(%3: i32, %4: i32):"), "{text}");
6284        assert!(text.contains("jump block1("), "{text}");
6285    }
6286
6287    #[test]
6288    fn a_comparison_used_as_a_condition_is_not_widened_and_narrowed_again() {
6289        let text = body("int f(int a, int b) { if (a < b) return 1; return 0; }\n");
6290        assert!(text.contains("icmp slt %0, %1"), "{text}");
6291        assert!(!text.contains("zext"), "{text}");
6292    }
6293
6294    #[test]
6295    fn the_right_side_of_a_short_circuit_is_in_a_block_of_its_own() {
6296        let text = body("int f(int a, int b) { return a && b; }\n");
6297        let expected = "\
6298block0(%0: i32, %1: i32):
6299    %2 = iconst.i32 0
6300    %3 = icmp ne %0, %2
6301    %4 = iconst.i1 0
6302    br_if %3, block1, block2(%4)
6303
6304block1:
6305    %5 = iconst.i32 0
6306    %6 = icmp ne %1, %5
6307    jump block2(%6)
6308
6309block2(%7: i1):
6310    %8 = zext.i32 %7
6311    return %8
6312";
6313        assert_eq!(text, expected);
6314    }
6315
6316    #[test]
6317    fn code_after_a_return_is_not_built_and_does_not_leave_an_empty_block_behind() {
6318        let text = body("int f(int a) { if (a) return 1; else return 2; return 3; }\n");
6319        // Three blocks, the test and the two arms. The join the `return 3` would need is
6320        // never created, because a block nothing branches to is not a block.
6321        assert!(!text.contains("block3"), "{text}");
6322        assert!(!text.contains("iconst.i32 3"), "{text}");
6323    }
6324
6325    #[test]
6326    fn falling_off_the_end_returns_zero_from_main_and_nothing_from_a_void_function() {
6327        assert!(body("int main(void) { }\n").contains("iconst.i32 0\n    return"));
6328        assert_eq!(body("void f(void) { }\n"), "block0:\n    return\n");
6329        assert!(body("int f(void) { }\n").contains("unreachable"));
6330    }
6331
6332    #[test]
6333    fn a_structure_is_copied_rather_than_held_in_a_value() {
6334        let text = body(
6335            "struct point { int x, y; };\n\
6336             int f(void) { struct point p = { 1, 2 }; struct point q = p; return q.x; }\n",
6337        );
6338        assert!(text.contains("memcpy"), "{text}");
6339    }
6340
6341    #[test]
6342    fn an_initializer_that_leaves_part_of_an_object_unwritten_zeroes_it_first() {
6343        let text = body("int f(void) { int a[4] = { 1 }; return a[3]; }\n");
6344        assert!(text.contains("memset"), "{text}");
6345    }
6346
6347    #[test]
6348    fn a_switch_is_one_branch_and_a_case_that_falls_through_carries_what_it_wrote() {
6349        let text = body(
6350            "int f(int x) { int r = 0; switch (x) { case 1: r = 1; case 2: r += 2; break; \
6351             default: r = 4; } return r; }\n",
6352        );
6353        let expected = "\
6354block0(%0: i32):
6355    %1 = iconst.i32 0
6356    switch %0, block1, [1 => block2, 2 => block3(%1)]
6357
6358block1:
6359    %2 = iconst.i32 4
6360    jump block4(%2)
6361
6362block2:
6363    %3 = iconst.i32 1
6364    jump block3(%3)
6365
6366block3(%4: i32):
6367    %5 = iconst.i32 2
6368    %6 = add.nsw %4, %5
6369    jump block4(%6)
6370
6371block4(%7: i32):
6372    return %7
6373";
6374        assert_eq!(text, expected);
6375    }
6376
6377    #[test]
6378    fn a_case_range_is_tested_for_rather_than_put_in_the_table() {
6379        // GNU's `case 1 ... 9`. Nine table entries would be nine here and four billion for the
6380        // range a program is allowed to write, so it is a subtraction and one unsigned compare.
6381        let text = body("int f(int x) { switch (x) { case 1 ... 9: return 1; } return 0; }\n");
6382        assert!(text.contains("%2 = sub %0, %1"), "{text}");
6383        assert!(text.contains("icmp ule"), "{text}");
6384        assert!(!text.contains("switch"), "{text}");
6385    }
6386
6387    #[test]
6388    fn break_leaves_the_switch_and_continue_leaves_the_loop_around_it() {
6389        let text = body(
6390            "int f(int n) { int t = 0; for (int i = 0; i < n; i++) { switch (i) { \
6391             case 0: continue; case 1: break; default: t += i; } t++; } return t; }\n",
6392        );
6393        // The `continue` goes to the step and the `break` goes to the `t++` after the switch,
6394        // which is also where the default falls out to.
6395        assert!(text.contains("switch %3, block4, [0 => block5, 1 => block6]"), "{text}");
6396        assert!(text.contains("block5:\n    jump block7("), "{text}");
6397        assert!(text.contains("block6:\n    jump block8("), "{text}");
6398    }
6399
6400    #[test]
6401    fn a_switch_with_nothing_to_branch_on_still_runs_what_comes_after_it() {
6402        assert_eq!(body("void f(int x) { switch (x) { } }\n"), "block0(%0: i32):\n    return\n");
6403    }
6404
6405    #[test]
6406    fn a_label_a_loop_is_only_entered_through_builds_the_loop_around_it() {
6407        // A branch into the middle of a loop that nothing else reaches, the Duff's device shape.
6408        // The `while` is not reached in order, so the walk starts a block nothing branches to and
6409        // builds it from there. What comes out is the loop with an edge straight into its body,
6410        // and the header that nothing arrives at is pruned.
6411        let text = body(
6412            "int f(int x, int n) { switch (x) { case 1: break; while (n) { case 2: n--; } } \
6413             return n; }\n",
6414        );
6415        // `case 2` lands on the body, `case 1` and the default land on the return, and the test
6416        // at the bottom of the loop comes back round to the body.
6417        assert!(text.contains("switch %0, block1(%1), [1 => block2, 2 => block3(%1)]"), "{text}");
6418        assert!(text.contains("block3(%3: i32):\n    %4 = iconst.i32 1"), "{text}");
6419        assert!(text.contains("block4:\n    jump block3("), "{text}");
6420    }
6421
6422    #[test]
6423    fn a_goto_into_a_loop_body_enters_it_without_the_test() {
6424        // The same thing through a `goto`. The first pass through the body runs whatever the
6425        // label is on, and only then does the loop reach its own test.
6426        let text = body("int f(int x, int n) { goto in; while (n) { in: n--; } return n; }\n");
6427        assert!(text.starts_with("block0(%0: i32, %1: i32):\n    jump block1(%1)"), "{text}");
6428        assert!(text.contains("block1(%2: i32):\n    %3 = iconst.i32 1"), "{text}");
6429        assert!(text.contains("br_if %6, block2, block3"), "{text}");
6430    }
6431
6432    #[test]
6433    fn a_goto_is_a_jump_to_the_block_the_label_starts() {
6434        let text = body("int f(int x) { int r = 0; if (x) goto out; r = 1; out: return r; }\n");
6435        // Both edges into `out` carry what `r` holds on the way, and neither is a stack slot. The
6436        // block the `goto` jumps out of is empty and hands its edge on, which is what moves `out`
6437        // up the block list to second place.
6438        assert!(!text.contains("alloca"), "{text}");
6439        assert!(text.contains("block2(%4: i32):\n    return %4"), "{text}");
6440        assert_eq!(text.matches("jump block2(").count(), 2, "{text}");
6441    }
6442
6443    #[test]
6444    fn a_backward_goto_is_a_loop_and_carries_what_it_changes() {
6445        let text =
6446            body("int f(int n) { int i = 0; again: if (i < n) { i++; goto again; } return i; }\n");
6447        assert!(!text.contains("alloca"), "{text}");
6448        assert!(text.contains("block1(%2: i32):"), "{text}");
6449        assert!(text.contains("jump block1(%5)"), "{text}");
6450    }
6451
6452    #[test]
6453    fn a_label_nothing_reaches_is_taken_out_rather_than_left_for_the_verifier() {
6454        // A block nothing branches to is not a legal function, and which labels are dead is not
6455        // known until the last statement has been walked, since the `goto` is allowed to be it.
6456        assert_eq!(
6457            body("int f(int x) { return x; spare: return 0; }\n"),
6458            "block0(%0: i32):\n    return %0\n"
6459        );
6460    }
6461
6462    #[test]
6463    fn a_bit_field_is_read_by_loading_the_bytes_it_lies_in_and_shifting() {
6464        let text = body(
6465            "struct s { unsigned a : 3; signed b : 5; };\nint f(struct s *p) { return p->b; }\n",
6466        );
6467        // One byte holds both fields, and the signed one needs no mask: shifting it down
6468        // arithmetically is what says its top bit is a sign.
6469        assert_eq!(
6470            text,
6471            "\
6472block0(%0: ptr):
6473    %1 = load.i8 %0, align 1
6474    %2 = iconst.i8 3
6475    %3 = ashr %1, %2
6476    %4 = sext.i32 %3
6477    return %4
6478"
6479        );
6480    }
6481
6482    #[test]
6483    fn a_store_to_a_bit_field_does_not_write_a_byte_it_has_no_bit_in() {
6484        // C11 says an ordinary member beside a bit-field is a memory location of its own, so
6485        // the four byte store this would take is a data race in a program that has none. The
6486        // three bytes of `a` go in as two and one, and `c` is not touched.
6487        let text =
6488            body("struct s { int a : 24; char c; };\nvoid f(struct s *p, int v) { p->a = v; }\n");
6489        assert_eq!(
6490            text,
6491            "\
6492block0(%0: ptr, %1: i32):
6493    %2 = iconst.i32 16777215
6494    %3 = and %1, %2
6495    %4 = trunc.i16 %3
6496    store %4 -> %0, align 2
6497    %5 = iconst.i32 16
6498    %6 = lshr %3, %5
6499    %7 = trunc.i8 %6
6500    %8 = iconst.i64 2
6501    %9 = ptr_add %0, %8
6502    store %7 -> %9, align 1
6503    return
6504"
6505        );
6506    }
6507
6508    #[test]
6509    fn what_an_assignment_to_a_bit_field_is_worth_is_what_fits_in_it() {
6510        let text =
6511            body("struct s { unsigned b : 5; };\nunsigned f(struct s *p) { return p->b = 33; }\n");
6512        // 33 does not fit in five bits, and 1 is both what goes in the field and what the
6513        // assignment is worth.
6514        assert!(text.contains("%3 = iconst.i8 31\n    %4 = and %2, %3"), "{text}");
6515        assert!(text.ends_with("%9 = zext.i32 %4\n    return %9\n"), "{text}");
6516    }
6517
6518    #[test]
6519    fn an_assignment_a_statement_throws_away_builds_none_of_what_it_is_worth() {
6520        // The value of an assignment to a bit-field takes a shift to build, and a statement
6521        // has no use for it. Nothing here reads back what was stored.
6522        let text = body("struct s { signed b : 5; };\nvoid f(struct s *p) { p->b = 3; }\n");
6523        assert_eq!(text.matches("ashr").count(), 0, "{text}");
6524        assert!(text.ends_with("store %8 -> %0, align 1\n    return\n"), "{text}");
6525    }
6526
6527    #[test]
6528    fn a_bit_field_in_an_initializer_goes_in_over_bytes_that_were_zeroed_first() {
6529        // A bit-field writes part of a byte and leaves the rest of it alone, so the object has
6530        // to be zero before it goes in or what the initializer did not name is whatever the
6531        // stack held.
6532        let text = body(
6533            "struct s { int a : 3; int b; };\nint f(void) { struct s v = { 1 }; return v.b; }\n",
6534        );
6535        assert!(text.contains("memset %0, %1, size 8, align 4"), "{text}");
6536    }
6537
6538    #[test]
6539    fn the_image_of_a_static_bit_field_is_the_bytes_the_fields_share() {
6540        // Two fields in one byte are not two entries in the image, because an image is written
6541        // in bytes: they are the byte they are both in.
6542        let text = ir("struct s { unsigned a : 3; unsigned b : 5; } g = { 1, 2 };\n");
6543        assert!(
6544            text.contains("global @g : bytes 4 = { bytes \"\\11\", zero 3 }, align 4"),
6545            "{text}"
6546        );
6547    }
6548
6549    #[test]
6550    fn an_initialized_flexible_array_member_makes_the_object_larger_than_its_type() {
6551        // `sizeof` answers without the array and the definition has to hold what was written, so
6552        // the object is the size of its image. gcc 16 gives these four, three and two bytes and
6553        // so does this. The image used to be written at the size the type had, which left the
6554        // verifier looking at twenty bytes going into four.
6555        let text = ir(concat!(
6556            "struct a { int i; int j[]; } x = { 1, { 2, 0, 2, 3 } };\n",
6557            "struct b { char c; char p[]; } y = { 'o', \"wx\" };\n",
6558            "struct c { char c; char p[]; } z = { '9', { 'e', 'b' } };\n",
6559            "char s[2] = \"hi\";\n",
6560        ));
6561        assert!(
6562            text.contains("global @x : bytes 20 = { i32 1, i32 2, i32 0, i32 2, i32 3 }"),
6563            "{text}"
6564        );
6565        assert!(text.contains("global @y : bytes 4 = { i8 111, bytes \"wx\\00\" }"), "{text}");
6566        assert!(text.contains("global @z : bytes 3 = { i8 57, i8 101, i8 98 }"), "{text}");
6567        // The array with a length of its own still cuts the literal down to it, which is the
6568        // one case in C where a string initializer drops its terminator.
6569        assert!(text.contains("global @s : bytes 2 = { bytes \"hi\" }"), "{text}");
6570    }
6571
6572    #[test]
6573    fn a_definition_takes_a_parameter_it_left_unnamed() {
6574        // The entry block's parameters are the definition's, and one the front end dropped for
6575        // having no name left the two lists different lengths, which the walk read as an
6576        // old-style definition and refused. gcc has taken these for far longer than C23 has.
6577        let text = ir("int f(int a, int) { return a; }\n");
6578        assert!(text.contains("func @f(i32, i32) -> i32"), "{text}");
6579        assert!(text.contains("block0(%0: i32, %1: i32):"), "{text}");
6580
6581        // The unnamed one first, so that the named one is the second parameter of the entry
6582        // block and not the first: the list says the order and not only how many there are.
6583        let text = ir("int g(int, int n) { return n; }\n");
6584        assert!(text.contains("block0(%0: i32, %1: i32):\n    return %1\n"), "{text}");
6585    }
6586
6587    #[test]
6588    fn an_assignment_of_a_structure_is_the_object_it_wrote() {
6589        // `d = e = c` used to be refused, because the middle assignment is a value of structure
6590        // type and the walk had nowhere to read one from. What an assignment is worth is the
6591        // value it stored, so the object it stored into is the answer and the chain is three
6592        // copies out of the one source with no temporary in it.
6593        let text = body(concat!(
6594            "struct s { int f; int g; };\n",
6595            "void h(struct s *a, struct s *c, struct s *d, struct s *e)\n",
6596            "{ *d = *e = a[0] = *c; }\n",
6597        ));
6598        assert_eq!(text.matches("memcpy").count(), 3, "{text}");
6599        assert!(text.contains("memcpy %8, %1, size 8, align 4\n"), "{text}");
6600        assert!(text.contains("memcpy %3, %8, size 8, align 4\n"), "{text}");
6601        assert!(text.contains("memcpy %2, %3, size 8, align 4\n"), "{text}");
6602    }
6603
6604    #[test]
6605    fn a_string_literal_stops_at_the_end_of_the_array_it_is_filling() {
6606        // The excess used to be laid into the object anyway, so the row after was written over
6607        // and the image refused the entry that came to it. C 6.7.10p14 says the terminator goes
6608        // in only if there is room for it, and gcc discards the rest of a literal that is longer
6609        // still, which is what the first of these is and why it warns.
6610        let mut opts = options();
6611        opts.emit = EmitKind::Ir;
6612        let result = run(
6613            &opts,
6614            concat!(
6615                "const char a[2][3] = { \"1234\", \"xyz\" };\n",
6616                "static const char b[3][5] = { \"12345\", \"678\", \"9\" };\n",
6617                "union u { struct { char x[4]; char y[4]; }; struct { char z[8]; }; };\n",
6618                "const union u c = { { \"1234\", \"567\" } };\n",
6619            ),
6620        );
6621        let text = result.text();
6622        assert_eq!(
6623            result.messages,
6624            ["/main.c:1:24: warning: initializer-string for array of 'const char' is too long \
6625              (5 chars into 3 available) [E0637]"]
6626        );
6627        assert!(text.contains("global @a : bytes 6 = { bytes \"123\", bytes \"xyz\" }"), "{text}");
6628        assert!(
6629            text.contains(
6630                "global @b : bytes 15 = { bytes \"12345\", bytes \"678\\00\", zero 1, \
6631                 bytes \"9\\00\", zero 3 }"
6632            ),
6633            "{text}"
6634        );
6635        // The eight bytes are four, three and a terminator, and then the byte the shorter
6636        // literal left for the string in the other member of the union to end at.
6637        assert!(
6638            text.contains("global @c : bytes 8 = { bytes \"1234\", bytes \"567\\00\" }"),
6639            "{text}"
6640        );
6641    }
6642
6643    #[test]
6644    fn a_cast_of_a_record_to_its_own_type_is_the_object_that_was_cast() {
6645        // gcc accepts one and does nothing with it, which sema already had. Lowering asked for
6646        // the object under it and had no arm for a cast, so `(struct s)x` in an initializer was
6647        // refused with E0519. It is one copy out of the object named, not two.
6648        let text = body(concat!(
6649            "struct s { int a, b; };\nstruct v { struct s s; int t; };\n",
6650            "void g(struct v *);\n",
6651            "void f(struct s *p) { struct v w = { (struct s)*p, 5 }; g(&w); }\n",
6652        ));
6653        assert_eq!(text.matches("memcpy").count(), 1, "{text}");
6654    }
6655
6656    #[test]
6657    fn a_compound_literal_read_in_a_static_initializer_lays_its_bytes_into_the_image() {
6658        // C 6.7.11p4 says a compound literal at file scope has static storage duration, which
6659        // makes it a constant element, and tcc and c-testsuite both write one. Sema used to call
6660        // it a non constant because reading it is a node of its own and the read was what it
6661        // looked at, and lowering had no way to put an object where it wanted a number.
6662        let text = ir(concat!(
6663            "struct s { int x; };\n",
6664            "struct t { struct s s; int o; } a = { (struct s){ 2 }, 3 };\n",
6665            "int n = (int){ 7 };\n",
6666            "struct u { struct s p; struct s q; } b = { (struct s){ 1 }, (struct s){ } };\n",
6667        ));
6668        assert!(text.contains("global @a : bytes 8 = { i32 2, i32 3 }"), "{text}");
6669        assert!(text.contains("global @n : i32 = 7,"), "{text}");
6670        // The second literal names nothing, so what it puts in is the zeros of its own size and
6671        // not the tail of the object it went in, which would have been the same bytes by luck.
6672        assert!(text.contains("global @b : bytes 8 = { i32 1, zero 4 }"), "{text}");
6673    }
6674
6675    #[test]
6676    fn the_address_of_a_compound_literal_asks_for_the_object_it_points_at() {
6677        // Nothing declares a compound literal, so the reference is the only thing that can ask
6678        // for it to be emitted. The image named `.Lanon.0` and the module defined no such
6679        // symbol, which the link would have been the first to find out.
6680        let text = ir("struct s { int x; };\nstruct s *q = &(struct s){ 9 };\n");
6681        assert!(text.contains("global @.Lanon.0 : i32 = 9, align 4, linkage(internal)"), "{text}");
6682        assert!(text.contains("global @q : bytes 8 = { addr.8 @.Lanon.0 }"), "{text}");
6683    }
6684
6685    #[test]
6686    fn an_object_of_no_size_at_all_has_an_image_with_nothing_in_it() {
6687        // A zero length array, which gcc allows and real code uses as the tail of a structure.
6688        // The image is there and holds nothing, which is not the global that has no image at
6689        // all, and the IR reader used to stop on the empty one.
6690        let text = ir("unsigned char foo[1][0];\n");
6691        assert!(text.contains("global @foo : bytes 0 = {}, align 1"), "{text}");
6692    }
6693
6694    #[test]
6695    fn a_null_pointer_in_an_image_is_the_bits_an_address_has_room_for() {
6696        // `NULL` in a static initializer, which every program has. The IR type is `ptr` and a
6697        // `ptr` has no width of its own, so the width the bits are cut to is the target's.
6698        let text = ir("void *p = 0;\nchar *q = (char *) 4096;\n");
6699        assert!(text.contains("global @p : i64 = 0, align 8"), "{text}");
6700        assert!(text.contains("global @q : i64 = 4096, align 8"), "{text}");
6701    }
6702
6703    #[test]
6704    fn an_object_another_module_defines_may_be_one_that_cannot_be_written_through() {
6705        // Which the verifier used to refuse, having read a declaration as a definition with
6706        // nothing in it. `extern const` is how a program names something in the library's read
6707        // only data, and glibc and Darwin both have one in a header a real program includes.
6708        let text = ir("extern const int limit;\nint f(void) { return limit; }\n");
6709        assert!(
6710            text.contains("global @limit : bytes 4, align 4, linkage(external), constant"),
6711            "{text}"
6712        );
6713    }
6714
6715    #[test]
6716    fn a_conditional_whose_value_is_an_object_answers_where_the_object_is() {
6717        // A structure is not a value in the IR, so the two arms cannot be joined as one. The
6718        // addresses can, and the answer is the address of whichever arm was taken rather than
6719        // a copy of it into a third place: both arms outlive the expression, so a copy would
6720        // be one nothing could observe. SQLite's parser writes one of these.
6721        let text = body(
6722            "\
6723struct s { int a, b; };
6724struct s pick(int c, struct s x, struct s y) { return c ? x : y; }
6725",
6726        );
6727        // The join takes an address, each arm hands it the one it has, and nothing is copied.
6728        assert!(text.contains("block3(%7: ptr)"), "{text}");
6729        assert!(text.contains("jump block3(%3)") && text.contains("jump block3(%4)"), "{text}");
6730        assert!(!text.contains("memcpy"), "the arms are joined rather than copied: {text}");
6731    }
6732
6733    /// GNU's `a ?: b` evaluates `a` once, and the arm answers the value that was tested.
6734    ///
6735    /// The checking keeps one node for `a` and converts it in two directions, to the bit the
6736    /// branch is taken on and to the type the whole expression has. Walking into the arm used to
6737    /// reach that node a second time and build a second copy of whatever it says, so `++i ?: 10`
6738    /// incremented twice and `f() ?: 10` called twice. Measured against gcc 16.2.0, which
6739    /// increments once.
6740    #[test]
6741    fn the_left_side_of_a_conditional_with_no_middle_is_evaluated_once() {
6742        let text = body("int f(int i) { return ++i ?: 10; }\n");
6743        assert!(text.contains("jump block3(%2)"), "the arm is the value that was tested: {text}");
6744        assert_eq!(text.matches("add.nsw").count(), 1, "incremented once: {text}");
6745
6746        // The arm still converts, since what the whole expression is worth is a `long` here and
6747        // the node under it is an `int`. What it converts is the value in hand.
6748        let text = body("long f(int i) { return ++i ?: 10L; }\n");
6749        assert!(text.contains("%5 = sext.i64 %2"), "the arm widens what was tested: {text}");
6750        assert_eq!(text.matches("add.nsw").count(), 1, "incremented once: {text}");
6751
6752        // A call, which is where evaluating twice is a wrong answer rather than a slow one.
6753        let text = body("int g(void);\nint f(void) { return g() ?: 10; }\n");
6754        assert_eq!(text.matches("call @g").count(), 1, "called once: {text}");
6755
6756        // Written out in full it is two reads of `i`, which is what C says it is, so the middle
6757        // operand being absent is the whole of the difference.
6758        let text = body("int f(int i) { return ++i ? ++i : 10; }\n");
6759        assert_eq!(text.matches("add.nsw").count(), 2, "incremented twice: {text}");
6760    }
6761
6762    #[test]
6763    fn a_structure_that_fits_in_registers_travels_as_the_registers_it_fits_in() {
6764        // `struct pair` is two eightbytes on SysV, one of them integer, so the signature says
6765        // one `i64` in each direction and the body takes the object apart and puts it back
6766        // together around the call.
6767        let text = ir("\
6768struct pair { int a, b; };
6769struct pair make(int a, int b);
6770struct pair twice(struct pair p) { return make(p.a, p.b); }
6771");
6772        assert!(text.contains("func @make(i32, i32) -> i64"), "{text}");
6773        assert!(text.contains("func @twice(i64) -> i64"), "{text}");
6774    }
6775
6776    #[test]
6777    fn a_structure_too_large_for_the_registers_travels_as_where_its_bytes_are() {
6778        // Over two eightbytes the caller passes the bytes in the argument area, which is
6779        // `byval`, and passes somewhere to write the return value, which is `sret`. Neither is
6780        // a parameter the program wrote and both are parameters the function has.
6781        let text = ir("\
6782struct big { double v[8]; };
6783struct big grow(struct big b);
6784struct big twice(struct big b) { return grow(grow(b)); }
6785");
6786        assert!(
6787            text.contains("func @grow(ptr sret(64, align 8), ptr byval(64, align 8))"),
6788            "{text}"
6789        );
6790        assert!(text.contains("block0(%0: ptr, %1: ptr):"), "{text}");
6791        // The inner call writes into a slot and the outer one reads the same slot, so the
6792        // object between the two calls is never copied anywhere.
6793        assert_eq!(text.matches("call @grow").count(), 2, "{text}");
6794    }
6795
6796    #[test]
6797    fn a_structure_passed_to_a_variadic_function_says_so_at_the_call() {
6798        // The bytes travel in the argument area the same way they would for a parameter, and
6799        // `printf` has no parameter there to say it on, so the call says it instead. The one
6800        // that fits in registers says nothing, because travelling as the registers it fits in
6801        // is what an argument does when nothing says otherwise.
6802        let text = ir("\
6803struct big { double v[8]; };
6804struct pair { int a, b; };
6805int p(const char *, ...);
6806int f(struct big b, struct pair q) { return p(\"\", 1, b, q); }
6807");
6808        assert!(
6809            text.contains("call @p(%4, %5, %2 byval(64, align 8), %6) : (ptr, ...) -> i32"),
6810            "{text}"
6811        );
6812    }
6813
6814    #[test]
6815    fn what_a_call_produced_is_somewhere_before_anything_is_read_out_of_it() {
6816        // `make(1, 2).b` has no object to read a member of until one is made, and what makes it
6817        // is a slot the returned registers are written to.
6818        let body = body(
6819            "\
6820struct pair { int a, b; };
6821struct pair make(int a, int b);
6822int second(void) { return make(1, 2).b; }
6823",
6824        );
6825        assert!(body.starts_with("block0:\n    %0 = alloca, size 8, align 4\n"), "{body}");
6826        assert!(body.contains("store %3 -> %0, align 4\n"), "{body}");
6827    }
6828
6829    #[test]
6830    fn a_structure_of_floats_travels_in_floating_point_registers_on_aarch64() {
6831        // The same declaration, classified by a different ABI: three `float` members are an
6832        // eightbyte of two of them and a half eightbyte of the third on SysV, and three vector
6833        // registers on AAPCS64.
6834        let source = "\
6835struct hfa { float x, y, z; };
6836int take(struct hfa h);
6837int give(struct hfa h) { return take(h); }
6838";
6839        assert!(ir(source).contains("func @take(f64, f32) -> i32"), "{}", ir(source));
6840        let mut opts = options();
6841        opts.emit = EmitKind::Ir;
6842        opts.target = "aarch64-unknown-linux-gnu".parse::<Triple>().unwrap();
6843        let result = run(&opts, source);
6844        assert_eq!(result.messages, Vec::<String>::new());
6845        assert!(result.text().contains("func @take(f32, f32, f32) -> i32"), "{}", result.text());
6846    }
6847
6848    #[test]
6849    fn an_array_whose_length_is_not_a_constant_is_a_slot_made_where_its_declaration_is() {
6850        // The size is a multiplication rather than a number, the slot is taken from the stack
6851        // where the declaration is, and the scope it was declared in gives it back.
6852        let source = "\
6853int use(int *);
6854void f(int n) {
6855  {
6856    int a[n];
6857    use(a);
6858  }
6859  use(0);
6860}
6861";
6862        let body = body(source);
6863        assert!(body.contains("mul.nsw"), "{body}");
6864        assert!(body.contains("stacksave"), "{body}");
6865        assert!(body.contains("alloca %"), "{body}");
6866        assert!(body.contains("stackrestore"), "{body}");
6867    }
6868
6869    #[test]
6870    fn a_goto_out_of_the_scope_of_one_gives_its_stack_back_on_the_way() {
6871        // The label is outside the block the array is in, so arriving there means the array is
6872        // gone, and the restore that says so goes in front of the branch. The `goto` is written
6873        // before the walk knows where the label is, which is why the restore is put there at
6874        // the end rather than built where the branch was.
6875        let source = "\
6876int use(int *);
6877int f(int n) {
6878  {
6879    int a[n];
6880    if (use(a)) goto out;
6881    use(0);
6882  }
6883out:
6884  return 0;
6885}
6886";
6887        let body = body(source);
6888        // Two ways out of the block and a restore on each: the jump and the end of the block.
6889        assert_eq!(body.matches("stackrestore").count(), 2, "{body}");
6890        let (_, after) = body.split_once("stackrestore").expect("the stack is given back");
6891        assert!(after.starts_with(" %4\n    jump block"), "{body}");
6892    }
6893
6894    #[test]
6895    fn a_goto_to_a_label_the_array_is_still_alive_at_leaves_the_stack_alone() {
6896        // The label is after the declaration and in the same block, so control that arrives
6897        // there arrives somewhere the array exists. Giving it back would be giving back an
6898        // object the next statement reads.
6899        let source = "\
6900int use(int *);
6901int f(int n) {
6902  int a[n];
6903again:
6904  if (use(a)) goto again;
6905  return 0;
6906}
6907";
6908        let body = body(source);
6909        assert!(body.contains("stacksave"), "{body}");
6910        assert!(!body.contains("stackrestore"), "{body}");
6911    }
6912
6913    #[test]
6914    fn a_goto_back_to_a_label_in_front_of_one_gives_it_back_every_time_round() {
6915        // A loop written out of a `goto`, with the array made inside it. The label is in the
6916        // same block as the declaration and before it, which is a place where the array does
6917        // not exist yet, so the jump there leaves its scope and has to give the stack back. A
6918        // compiler that skips this restore grows the stack once per iteration.
6919        let source = "\
6920int use(int *);
6921int f(int n) {
6922again:
6923  {
6924    int a[n];
6925    if (use(a)) goto again;
6926  }
6927  return 0;
6928}
6929";
6930        let body = body(source);
6931        assert_eq!(body.matches("stacksave").count(), 1, "{body}");
6932        let (_, after) = body.split_once("stackrestore").expect("the stack is given back");
6933        assert!(after.starts_with(" %4\n    jump block1\n"), "{body}");
6934    }
6935
6936    #[test]
6937    fn the_head_of_a_for_loop_is_a_scope_that_closes_where_the_loop_is_left() {
6938        // The scope opened for `for (int a[n];;)` used to stay open, and a scope left open is
6939        // not one mark nobody reads. The marks are a stack, so the next close took this one
6940        // instead of its own, and the body of the loop gave back nothing while the block after
6941        // the loop restored a pointer saved inside it. The verifier refused that, which is how
6942        // it was found.
6943        let source = "\
6944int f(void);
6945void t(void) {
6946  int count = 10;
6947  for (; count--;) {
6948    int b[f()];
6949    int i;
6950    for (i = 0; i < f(); i++) {
6951      b[i] = count;
6952    }
6953  }
6954}
6955";
6956        let body = body(source);
6957        // One save, in the body, and one restore for it, also in the body: the block the
6958        // restore is in is the one the inner loop leaves through, and it goes back round the
6959        // outer loop rather than out of it.
6960        assert_eq!(body.matches("stacksave").count(), 1, "{body}");
6961        let (_, after) = body.split_once("stackrestore").expect("the stack is given back");
6962        // The rest of the block the restore is in, which is the last block here, so there is not
6963        // always another one after it to split on.
6964        let next = after.split("\n\n").next().expect("the block the restore is in");
6965        assert!(next.contains("jump block1("), "{body}");
6966    }
6967
6968    #[test]
6969    fn how_long_one_of_those_is_was_decided_where_it_was_declared_and_not_where_it_is_asked() {
6970        // What C says about the length being evaluated once: `sizeof a` after `n` changed is
6971        // still as long as the array is, which is what `n` was when the array came into being.
6972        let source = "\
6973unsigned long f(int n) {
6974  int a[n];
6975  n = 0;
6976  return sizeof a;
6977}
6978";
6979        let body = body(source);
6980        // One read of the parameter, at the declaration, and the answer is built out of it.
6981        assert_eq!(body.matches("sext.i64 %0").count(), 2, "{body}");
6982    }
6983
6984    #[test]
6985    fn a_block_in_the_middle_of_an_expression_is_walked_where_the_expression_is() {
6986        // GNU's statement expression: the statements happen where they are written and the last
6987        // one is the value, so the temporary in it never becomes a slot and never is copied.
6988        let source = "\
6989int use(int);
6990int f(int x) {
6991  return ({
6992    int t = use(x);
6993    t * t;
6994  });
6995}
6996";
6997        let expected = "\
6998block0(%0: i32):
6999    %1 = call @use(%0) : (i32) -> i32
7000    %2 = mul.nsw %1, %1
7001    return %2
7002";
7003        assert_eq!(body(source), expected);
7004    }
7005
7006    #[test]
7007    fn one_of_those_that_control_never_leaves_is_lowered_and_what_follows_it_is_dropped() {
7008        // A macro that always jumps, which is what this shape is in real code. The value is
7009        // never taken, and the block the rest of the expression would have been built in is
7010        // one nothing branches to, so it goes with the other unreachable blocks.
7011        let source = "int f(int x) { return ({ return x; 0; }); }\n";
7012        assert_eq!(body(source), "block0(%0: i32):\n    return %0\n");
7013    }
7014
7015    #[test]
7016    fn one_argument_off_a_variable_argument_list_stays_an_intrinsic() {
7017        // What it becomes is the target's answer, and this is not where the target's answers
7018        // are, so the walk writes down which list and which type and leaves it at that. Two of
7019        // them are two instructions, since each moves the list on.
7020        let source = "double f(__builtin_va_list ap) { return __builtin_va_arg(ap, double) + __builtin_va_arg(ap, double); }\n";
7021        let expected = "\
7022block0(%0: ptr):
7023    %1 = va_arg.f64 %0
7024    %2 = va_arg.f64 %0
7025    %3 = fadd %1, %2
7026    return %3
7027";
7028        assert_eq!(body(source), expected);
7029    }
7030
7031    #[test]
7032    fn one_that_reads_a_structure_answers_where_the_object_is() {
7033        // An aggregate is not a value, so there is nothing for the result of `va_arg` to be and
7034        // the object form is a second instruction. What it answers is an address, so it is a
7035        // place already and the walk copies nothing out of it: the copy here is the one the
7036        // initializer asks for, into the variable being declared. The size and the alignment
7037        // travel with it because they are what steps the list on and what a target that has to
7038        // put registers somewhere needs to know. So does the classification, which says the two
7039        // halves of this one arrived in general purpose registers: that is an answer about a C
7040        // type, and this is the last place that still has one.
7041        //
7042        // The slot is aligned to sixteen and the copy into it to eight, which is not a
7043        // disagreement. Sixteen is what a local aggregate of sixteen bytes gets whatever its
7044        // members ask for, and eight is what the type asks for and so what the copy may assume
7045        // about the object it is reading from.
7046        let source = "\
7047struct s { int a; long b; };
7048long f(__builtin_va_list ap) { struct s v = __builtin_va_arg(ap, struct s); return v.b; }
7049";
7050        let expected = "\
7051block0(%0: ptr):
7052    %1 = alloca, size 16, align 16
7053    %2 = va_object %0, size 16, align 8, in(int 8 at 0, int 8 at 8)
7054    memcpy %1, %2, size 16, align 8
7055    %3 = iconst.i64 8
7056    %4 = ptr_add %1, %3
7057    %5 = load.i64 %4, align 8, tbaa !1
7058    return %5
7059";
7060        assert_eq!(body(source), expected);
7061    }
7062
7063    /// Which register file each eightbyte arrived in is the whole of what the classification adds,
7064    /// and an object with no slots at all is one it sent to the caller's argument area, which is
7065    /// what everything over two eightbytes is whatever its members are.
7066    #[test]
7067    fn the_classification_says_which_registers_the_object_arrived_in() {
7068        let source = "\
7069struct s { double a; double b; };
7070double f(__builtin_va_list ap) { struct s v = __builtin_va_arg(ap, struct s); return v.a; }
7071";
7072        assert!(
7073            body(source)
7074                .contains("va_object %0, size 16, align 8, in(float f64 at 0, float f64 at 8)"),
7075            "{}",
7076            body(source)
7077        );
7078
7079        let big = "\
7080struct s { long a[4]; };
7081long f(__builtin_va_list ap) { struct s v = __builtin_va_arg(ap, struct s); return v.a[0]; }
7082";
7083        assert!(body(big).contains("va_object %0, size 32, align 8\n"), "{}", body(big));
7084    }
7085
7086    #[test]
7087    fn a_jump_to_an_address_branches_to_every_label_the_function_takes_the_address_of() {
7088        // GNU's computed goto. Which label the address holds is not known here, so all of them
7089        // are listed, and the values arriving at one are passed on every edge the same way they
7090        // are on an ordinary branch.
7091        let source = "\
7092int f(int c) {
7093  void *p = c ? &&one : &&two;
7094  goto *p;
7095one:
7096  return 1;
7097two:
7098  return 2;
7099}
7100";
7101        let expected = "\
7102block0(%0: i32):
7103    %1 = iconst.i32 0
7104    %2 = icmp ne %0, %1
7105    br_if %2, block1, block2
7106
7107block1:
7108    %3 = block_addr block3
7109    jump block4(%3)
7110
7111block2:
7112    %4 = block_addr block5
7113    jump block4(%4)
7114
7115block3:
7116    %5 = iconst.i32 1
7117    return %5
7118
7119block4(%6: ptr):
7120    indirect_br %6, block3, block5
7121
7122block5:
7123    %7 = iconst.i32 2
7124    return %7
7125";
7126        assert_eq!(body(source), expected);
7127    }
7128
7129    #[test]
7130    fn a_jump_to_an_address_no_label_in_the_function_has_arrives_nowhere() {
7131        // The address came from outside the function, and a jump to a label in another function
7132        // is undefined. The expression is still evaluated, since a call in it has to happen.
7133        let source = "void **next(void);
7134void f(void) { goto *next(); }
7135";
7136        let expected = "\
7137block0:
7138    %0 = call @next() : () -> ptr
7139    unreachable
7140";
7141        assert_eq!(body(source), expected);
7142    }
7143
7144    #[test]
7145    fn an_asm_with_no_operands_is_volatile_and_the_clobbers_are_the_whole_of_what_it_says() {
7146        // Nothing reads a result, so the only thing that keeps it is that it is volatile, which
7147        // a basic asm implies.
7148        let source = "void f(void) { __asm__(\"mfence\" ::: \"memory\"); }\n";
7149        let expected = "\
7150block0:
7151    inline_asm.volatile \"mfence\", \"\", \"memory\"()
7152    return
7153";
7154        assert_eq!(body(source), expected);
7155    }
7156
7157    #[test]
7158    fn the_constraints_are_one_list_in_the_order_the_template_counts_the_operands() {
7159        // The outputs first and then the inputs, which is the numbering `%0` and `%1` use. An
7160        // output in a register is a result, and one that is read as well is an argument too.
7161        let source = "\
7162int f(int x, int y) {
7163  int r;
7164  __asm__(\"addl %2, %0\" : \"=r\"(r), \"+r\"(y) : \"r\"(x));
7165  return r + y;
7166}
7167";
7168        let expected = "\
7169block0(%0: i32, %1: i32):
7170    %2, %3 = inline_asm.(i32, i32) \"addl %2, %0\", \"=r,+r,r\", \"\"(%1, %0)
7171    %4 = add.nsw %2, %3
7172    return %4
7173";
7174        assert_eq!(body(source), expected);
7175    }
7176
7177    #[test]
7178    fn a_memory_operand_travels_as_the_address_of_an_object_that_is_given_a_slot() {
7179        // The assembly is handed a pointer, so the object cannot live in a value, and the scan
7180        // that runs before the walk has to have known that or there would be nothing to point
7181        // at. A structure travels this way whatever else its constraint allows, since there is
7182        // no register that holds one.
7183        let source = "\
7184struct pair { int a, b; };
7185int f(int x) {
7186  int slot = x;
7187  struct pair p = { x, x };
7188  __asm__(\"incl %0\" : \"+m\"(slot), \"=m\"(p));
7189  return slot + p.a;
7190}
7191";
7192        let text = body(source);
7193        assert!(text.contains("inline_asm \"incl %0\", \"+m,=m\", \"\"(%1, %2)\n"), "{text}");
7194        assert!(text.contains("%1 = alloca, size 4, align 4\n"), "{text}");
7195        assert!(text.contains("%2 = alloca, size 8, align 4\n"), "{text}");
7196    }
7197
7198    #[test]
7199    fn an_asm_goto_falls_through_to_its_first_target_and_writes_its_outputs_there() {
7200        // The output is only in scope where the instruction dominates, which is the fall through
7201        // block, so the edge to the label carries the value the object had before the assembly
7202        // ran. That is what document 11 asks for and it is what putting the fall through first
7203        // buys.
7204        let source = "\
7205int f(int x) {
7206  int r = 7;
7207  __asm__ goto(\"cbnz %0, %l1\" : \"=r\"(r) : \"r\"(x) :: away);
7208  return r;
7209away:
7210  return r;
7211}
7212";
7213        let expected = "\
7214block0(%0: i32):
7215    %1 = iconst.i32 7
7216    %2 = inline_asm.volatile \"cbnz %0, %l1\", \"=r,r\", \"\"(%0), labels [block1, block2]
7217
7218block1:
7219    return %2
7220
7221block2:
7222    return %1
7223";
7224        assert_eq!(body(source), expected);
7225    }
7226
7227    #[test]
7228    fn an_asm_statement_that_is_not_well_formed_is_reported_in_the_words_gcc_uses() {
7229        // The operands are checked here rather than by the assembler, because by the time the
7230        // assembler sees the template the operands have become registers and it has nothing left
7231        // to say about the C that named them.
7232        let mut opts = options();
7233        opts.emit = EmitKind::Ir;
7234        for (source, expected) in [
7235            (
7236                "void f(int x) { __asm__(\"\" : \"r\"(x)); }\n",
7237                "output operand constraint lacks '='",
7238            ),
7239            (
7240                "void f(int x) { __asm__(\"\" : \"=r\"(x + 1)); }\n",
7241                "lvalue required in 'asm' statement",
7242            ),
7243            (
7244                "const int g = 1;\nvoid f(void) { __asm__(\"\" : \"=r\"(g)); }\n",
7245                "read-only variable 'g' used as 'asm' output",
7246            ),
7247            (
7248                "void f(int x) { __asm__(\"\" : : \"=r\"(x)); }\n",
7249                "input operand constraint contains '='",
7250            ),
7251            (
7252                "void f(void) { __asm__(\"\" : : \"m\"(1)); }\n",
7253                "memory input 0 is not directly addressable",
7254            ),
7255            ("void f(void) { __asm__(L\"\"); }\n", "wide string literal in 'asm'"),
7256            (
7257                "void f(int x, int y) { __asm__(\"\" : [a] \"=r\"(x) : [a] \"r\"(y)); }\n",
7258                "duplicate asm operand name 'a'",
7259            ),
7260            ("void f(int x) { __asm__(\"%[in]\" : \"=r\"(x)); }\n", "undefined named operand 'in'"),
7261        ] {
7262            let result = run(&opts, source);
7263            assert!(result.failed(), "expected this to be reported:\n{source}");
7264            assert!(
7265                result.messages.iter().any(|m| m.contains(expected)),
7266                "{expected}\n{:?}",
7267                result.messages
7268            );
7269        }
7270    }
7271
7272    /// An `asm` at file scope whose template is directives is the whole of what the incbin
7273    /// header, an alias table and a hand written jump table each write, and what it says is a
7274    /// section holding named bytes. So it becomes the globals it names, in the order it names
7275    /// them, which is what `spec/11-asm-objects-debug.md` section 11.2 asks for.
7276    #[test]
7277    fn an_asm_at_file_scope_that_is_directives_becomes_the_objects_it_defines() {
7278        let text = ir(concat!(
7279            "__asm__(\n",
7280            "  \".section .rodata\\n\"\n",
7281            "  \".globl first\\n\"\n",
7282            "  \".balign 8\\n\"\n",
7283            "  \"first:\\n\"\n",
7284            "  \".long 1\\n\"\n",
7285            "  \".long 2\\n\"\n",
7286            "  \".globl last\\n\"\n",
7287            "  \"last:\\n\"\n",
7288            "  \".quad last - first\\n\");\n",
7289            "extern const int first[];\n",
7290            "extern const long last;\n",
7291        ));
7292        assert!(text.contains("global @first : bytes 8 = { i32 1, i32 2 }, align 8"), "{text}");
7293        assert!(text.contains("global @last : i64 = 8"), "{text}");
7294    }
7295
7296    /// The distance between two labels is what the incbin header hands a program as the size of
7297    /// the data, so a declaration of one of the names has to find the definition the template
7298    /// made rather than turn it back into something the linker is asked for.
7299    #[test]
7300    fn a_name_an_asm_at_file_scope_defined_is_not_undone_by_a_declaration_of_it() {
7301        let text = ir(concat!(
7302            "__asm__(\".data\\n.globl counter\\ncounter:\\n.long 7\\n\");\n",
7303            "extern int counter;\n",
7304            "int read(void) { return counter; }\n",
7305        ));
7306        assert!(text.contains("global @counter : i32 = 7"), "{text}");
7307    }
7308
7309    /// `.incbin` is the one directive that reads something, and what it reads comes through the
7310    /// same file system the sources did.
7311    #[test]
7312    fn an_incbin_at_file_scope_is_the_bytes_of_the_file_it_names() {
7313        let mut opts = options();
7314        opts.emit = EmitKind::Ir;
7315        let mut fs = MemoryFileSystem::new();
7316        fs.insert(
7317            "/main.c",
7318            b"__asm__(\".data\\n.globl blob\\nblob:\\n.incbin \\\"seed\\\"\\n\");\n".to_vec(),
7319        );
7320        fs.insert("seed", b"hi".to_vec());
7321        let result = compile(&opts, "/main.c", &fs);
7322        assert_eq!(result.messages, Vec::<String>::new());
7323        let text = result.text();
7324        assert!(text.contains("global @blob : bytes 2 = { bytes \"hi\" }"), "{text}");
7325    }
7326
7327    /// A file that is not there is the mistake a build makes when it runs the compiler from the
7328    /// wrong directory, and it is worth saying which file rather than saying the template failed.
7329    #[test]
7330    fn an_incbin_naming_a_file_that_is_not_there_says_which_file() {
7331        let messages = errors("__asm__(\".data\\nb:\\n.incbin \\\"nowhere\\\"\\n\");\n");
7332        assert!(
7333            messages
7334                .iter()
7335                .any(|m| m.contains("cannot open 'nowhere' for reading") && m.contains("E0702")),
7336            "{messages:?}"
7337        );
7338    }
7339
7340    /// The line drawn is the same one the `asm` inside a function draws: directives are read and
7341    /// an instruction waits for an assembler. Refusing by name is what makes the wait visible.
7342    #[test]
7343    fn an_instruction_in_an_asm_at_file_scope_is_refused_rather_than_ignored() {
7344        for source in [
7345            "__asm__(\".text\\n.globl f\\nf:\\n  ret\\n\");\n",
7346            "__asm__(\".data\\n.set alias, 4\\n\");\n",
7347        ] {
7348            let messages = errors(source);
7349            assert!(
7350                messages
7351                    .iter()
7352                    .any(|m| m.contains("not supported yet")
7353                        && m.contains("in an `asm` at file scope")),
7354                "{source}\n{messages:?}"
7355            );
7356        }
7357    }
7358
7359    #[test]
7360    fn what_the_walk_cannot_build_yet_is_reported_rather_than_mislowered() {
7361        let mut opts = options();
7362        opts.emit = EmitKind::Ir;
7363        for source in [
7364            "int f(int n) { void *p = &&out; if (n) goto *p; { int a[n]; out: return 1; } }\n",
7365            "int f(int n) { int a[n]; __asm__ goto(\"\" ::::out); out: return a[0]; }\n",
7366        ] {
7367            let result = run(&opts, source);
7368            assert!(result.failed(), "expected this to be reported:\n{source}");
7369            assert!(
7370                result.messages.iter().any(|m| m.contains("not supported yet")),
7371                "{:?}",
7372                result.messages
7373            );
7374        }
7375    }
7376
7377    /// Compiles `source` to IR, reads that back as an input, and gives back both texts.
7378    fn round_trip(source: &str) -> (String, String) {
7379        let printed = ir(source);
7380        let mut opts = options();
7381        opts.emit = EmitKind::Ir;
7382        let mut fs = MemoryFileSystem::new();
7383        fs.insert("/main.ir", printed.clone().into_bytes());
7384        let result = compile_ir(&opts, "/main.ir", &fs);
7385        assert_eq!(result.messages, Vec::<String>::new(), "expected this to read back:\n{printed}");
7386        (printed, result.text().to_owned())
7387    }
7388
7389    #[test]
7390    fn ir_that_arrives_as_an_input_is_read_back_and_written_out_the_same() {
7391        // The other half of the round trip test below, through the driver rather than through
7392        // the library, which is what makes the property something to run over a real program
7393        // rather than over the modules a test builds.
7394        let (printed, again) = round_trip(
7395            "struct point { int x, y; };\n             static const char greeting[] = \"hi\";\n             int puts(const char *);\n             int f(int n) { struct point p = { n, 1 }; puts(greeting); return p.x; }\n",
7396        );
7397        assert_eq!(printed, again);
7398    }
7399
7400    #[test]
7401    fn ir_that_is_not_ir_says_which_line_stopped_it() {
7402        let mut opts = options();
7403        opts.emit = EmitKind::Ir;
7404        let mut fs = MemoryFileSystem::new();
7405        let text = "\
7406; ModuleID = 'a.c'
7407; format 0
7408target triple = \"x86_64-unknown-linux-gnu\"
7409target datalayout = \"e-p:64:64-i64:64-S128\"
7410
7411func @f(), linkage(external) {
7412block0:
7413    frobnicate
7414}
7415";
7416        fs.insert("/main.ir", text.as_bytes().to_vec());
7417        let result = compile_ir(&opts, "/main.ir", &fs);
7418        assert!(result.failed());
7419        assert!(result.messages[0].contains("/main.ir:8"), "{:?}", result.messages);
7420    }
7421
7422    #[test]
7423    fn ir_that_reads_but_does_not_hold_together_is_reported_by_the_verifier() {
7424        // A module that a person edited has not been through the verifier, and the return of
7425        // an `i32` from a function that returns nothing is the kind of thing editing produces.
7426        let mut opts = options();
7427        opts.emit = EmitKind::Ir;
7428        let mut fs = MemoryFileSystem::new();
7429        let text = "\
7430; ModuleID = 'a.c'
7431; format 0
7432target triple = \"x86_64-unknown-linux-gnu\"
7433target datalayout = \"e-p:64:64-i64:64-S128\"
7434
7435func @f(), linkage(external) {
7436block0:
7437    %0 = iconst.i32 1
7438    return %0
7439}
7440";
7441        fs.insert("/main.ir", text.as_bytes().to_vec());
7442        let result = compile_ir(&opts, "/main.ir", &fs);
7443        assert!(result.failed());
7444        assert!(result.messages[0].contains("invalid IR"), "{:?}", result.messages);
7445    }
7446
7447    #[test]
7448    fn a_typed_tree_is_not_something_an_input_of_ir_can_produce() {
7449        // The C that became this is not here any more, so there is nothing to print a tree of.
7450        let mut fs = MemoryFileSystem::new();
7451        fs.insert("/main.ir", Vec::new());
7452        let result = compile_ir(&options(), "/main.ir", &fs);
7453        assert!(result.failed());
7454        assert!(result.messages[0].contains("can only be emitted as IR"), "{:?}", result.messages);
7455    }
7456
7457    #[test]
7458    fn the_printed_ir_reads_back_as_the_same_module() {
7459        // The M2 exit criterion: the text is the module and nothing about it is lost by
7460        // writing it down. Anything the printer invents or the parser drops shows up here.
7461        let text = ir("\
7462struct point { int x, y; };
7463static const char greeting[] = \"hi\";
7464int table[4] = { 1, 2, 3 };
7465int puts(const char *);
7466double half(double x) { return x / 2.0; }
7467int f(int n) {
7468  int total = 0;
7469  for (int i = 0; i < n; i++) {
7470    if (i == 3) continue;
7471    total += table[i];
7472  }
7473  switch (n) {
7474    case 0: total = 1;
7475    case 1: total++; break;
7476    default: total = -total;
7477  }
7478  struct point p = { total, 1 };
7479  int *q = &p.y;
7480  puts(greeting);
7481  return p.x + *q;
7482}
7483int dispatch(int c) {
7484  void *p = c ? &&one : &&two;
7485  goto *p;
7486one:
7487  return 1;
7488two:
7489  return 2;
7490}
7491int assembly(int x, int *p) {
7492  int r;
7493  __asm__ volatile(\"xadd %0, %2\" : \"=r\"(r), \"+m\"(*p) : \"0\"(x) : \"cc\");
7494  __asm__ goto(\"cbnz %0, %l1\" : : \"r\"(r) : : away);
7495  return r;
7496away:
7497  return 0;
7498}
7499");
7500        let mut names = Interner::new();
7501        let module = rucc_ir::parse(&text, &mut names).expect("the printer writes what it reads");
7502        assert_eq!(rucc_ir::print(&module, &names), text);
7503    }
7504
7505    #[test]
7506    fn what_save_temps_keeps_is_the_text_that_was_compiled_and_the_assembly_that_was_assembled() {
7507        // The point of the flag is that these two are the compilation rather than a description
7508        // of one, so both come out of the run that produced the object rather than out of a
7509        // second run under different flags.
7510        let mut opts = options();
7511        opts.emit = EmitKind::Object;
7512        opts.save_temps = rucc_session::SaveTemps::Object;
7513        let result = run(&opts, "#define N 2\nint a[N];\n");
7514        assert_eq!(result.messages, Vec::<String>::new());
7515        let text = result.temps.preprocessed.expect("the preprocessed text");
7516        assert!(text.contains("int a[2];"), "{text}");
7517        assert!(text.starts_with("# 1 \"/main.c\""), "{text}");
7518        let asm = result.temps.assembly.expect("the assembly");
7519        assert!(asm.contains("a:"), "{asm}");
7520        assert!(matches!(result.artifact, Artifact::Object { .. }), "{:?}", result.artifact);
7521    }
7522
7523    #[test]
7524    fn nothing_is_kept_unless_the_flag_asked_for_it() {
7525        // A compilation that was not asked to keep anything must not pay for printing text
7526        // nobody will read, and the empty value is what says so.
7527        let mut opts = options();
7528        opts.emit = EmitKind::Object;
7529        assert_eq!(run(&opts, "int a;\n").temps, Temps::default());
7530    }
7531
7532    #[test]
7533    fn a_compilation_that_stops_before_the_back_end_keeps_the_text_and_no_assembly() {
7534        // `--emit=ir` never produces any, and the text is worth keeping all the same: it is
7535        // what a report about the file being read wrongly has to have in it.
7536        let mut opts = options();
7537        opts.emit = EmitKind::Ir;
7538        opts.save_temps = rucc_session::SaveTemps::Cwd;
7539        let result = run(&opts, "int a;\n");
7540        assert!(result.temps.preprocessed.is_some());
7541        assert_eq!(result.temps.assembly, None);
7542    }
7543}