From 50e4a310db240eeb676b20f4ab5cbed497765675 Mon Sep 17 00:00:00 2001 From: tamnd Date: Sun, 6 Sep 2026 17:14:06 +0700 Subject: [PATCH] F02, the preprocessor is not a text editor The second lesson of M3. F01 showed the language the driver's decisions are written in. This one goes inside the first program the driver runs. The lesson is built on one demonstration: `#define EMPTY` and then `a+EMPTY+b`, which prints `a+ +b`. Text substitution gives `a++b`. The space is in no input file, and it is there because an empty expansion leaves a padding token and cpp_avoid_paste was asked whether `+` may be printed against `+`. Thirty eight token pairs were probed the same way. Twenty nine came back separated and nine did not, and the nine are the ones that do not lex as a single token. gxray.cpp reads recorded preprocessor output: macro tables, line markers, -H traces, expansion demonstrations. It never expands a macro, because expanding one needs the include path, the target's macros, the date and a hash table with the state of every other macro in it. The corpus holds five macro tables, six expansions, the thirty eight probes and four include traces, on aarch64 Darwin and x86-64 Linux. 443 macros against 408, 373 names shared, and 50 of the shared names defined to different text, which is the set #ifdef cannot see. One #include opens 42 files on one machine and 31 on the other, and the two sets have no path in common. Four headers differing by one line measure the multiple include optimization: a comment after the #endif costs nothing, one declaration costs the whole thing. -H names neither of them, because report_missing_guard only reports a file whose stack_count is 1, so the advice arrives for the header that has not cost anything yet. tests/test_cpp.py compares the table of paste-avoiding pairs against the case labels of cpp_avoid_paste in the pinned tree, so a GCC that grows a case fails the build rather than making a paragraph quietly false. BP-CPP goes from stub to partial: the 32-byte token and its 13 flags, the 90 token types and the four positions in the table, the hash node, the macro, the 20 built-ins of which -dM prints one; cpp_get_token_1, argument prescan, pasting by re-lexing, the two flags behind blue paint, the nine places that maintain the include guard state, and the printer's two independent reasons to print a space. The glossary's `token` entry said twenty four bytes. libcpp's own comment says thirty two on a 64-bit host. --- GLOSSARY.md | 62 +- README.md | 3 +- blueprints/BP-CPP.md | 607 ++++ citations.lock.json | 416 +++ corpora/cpp/f02.json | 420 +++ corpora/source/f02.json | 339 ++ docs/blueprints.md | 7 +- docs/blueprints/BP-CPP.md | 3 + docs/lessons.md | 3 +- gxray/cpp.py | 643 ++++ gxray/glossary.py | 71 + lessons/CLAIMS.md | 22 +- lessons/f02-tokens-not-text/build.py | 788 +++++ lessons/f02-tokens-not-text/f02.ipynb | 1176 +++++++ lessons/f02-tokens-not-text/grade.py | 135 + lessons/f02-tokens-not-text/record.py | 723 +++++ site/mkdocs.yml | 1 + tests/test_cpp.py | 413 +++ tests/test_tier0.py | 6 +- .../32/32e12e027eab29cf8c9c8bdded42e8ab.json | 2841 +++++++++++++++++ .../6e/6e056683d5f98988c2723fa1411181ea.json | 48 + .../8c/8c6c8a242b28ac906e721b4315f002c7.json | 43 + .../b0/b052b8da4cb7550d4d587e32552932fe.json | 43 + .../b8/b8aad3f4e7ae4a0cd93b6026890dd086.json | 48 + .../bb/bb11d647f8eaf8ed57950802ec869710.json | 2073 ++++++++++++ .../ef/ef9027019a0b32786c5c64e0e0652d71.json | 43 + tools/tier0/experiments.toml | 17 + 27 files changed, 10988 insertions(+), 6 deletions(-) create mode 100644 blueprints/BP-CPP.md create mode 100644 corpora/cpp/f02.json create mode 100644 corpora/source/f02.json create mode 100644 docs/blueprints/BP-CPP.md create mode 100644 gxray/cpp.py create mode 100644 lessons/f02-tokens-not-text/build.py create mode 100644 lessons/f02-tokens-not-text/f02.ipynb create mode 100644 lessons/f02-tokens-not-text/grade.py create mode 100644 lessons/f02-tokens-not-text/record.py create mode 100644 tests/test_cpp.py create mode 100644 tools/cecache/store/32/32e12e027eab29cf8c9c8bdded42e8ab.json create mode 100644 tools/cecache/store/6e/6e056683d5f98988c2723fa1411181ea.json create mode 100644 tools/cecache/store/8c/8c6c8a242b28ac906e721b4315f002c7.json create mode 100644 tools/cecache/store/b0/b052b8da4cb7550d4d587e32552932fe.json create mode 100644 tools/cecache/store/b8/b8aad3f4e7ae4a0cd93b6026890dd086.json create mode 100644 tools/cecache/store/bb/bb11d647f8eaf8ed57950802ec869710.json create mode 100644 tools/cecache/store/ef/ef9027019a0b32786c5c64e0e0652d71.json diff --git a/GLOSSARY.md b/GLOSSARY.md index 3107c26..4d21b7c 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -8,7 +8,7 @@ This file is generated from `gxray/glossary.py`. Edit that and run `just build-g ## Index -[DejaGnu](#dejagnu) | [GENERIC](#generic) | [GIMPLE](#gimple) | [IRA](#ira) | [LRA](#lra) | [RTL](#rtl) | [RTX](#rtx) | [SSA](#ssa) | [SSA name](#ssa-name) | [TODO flags](#todo-flags) | [allocno](#allocno) | [alternative](#alternative) | [assembler directive](#assembler-directive) | [back end](#back-end) | [basic block](#basic-block) | [bootstrap](#bootstrap) | [bubbling](#bubbling) | [build config](#build-config) | [cc1](#cc1) | [checking build](#checking-build) | [collect2](#collect2) | [compiler table](#compiler-table) | [constraint](#constraint) | [control flow graph](#control-flow-graph) | [cross compiler](#cross-compiler) | [current function](#current-function) | [debug counter](#debug-counter) | [default definition](#default-definition) | [define_insn](#define_insn) | [definition](#definition) | [directive](#directive) | [dominance](#dominance) | [driver](#driver) | [dump file](#dump-file) | [edge](#edge) | [effective target](#effective-target) | [excess errors](#excess-errors) | [expand](#expand) | [final](#final) | [front end](#front-end) | [garbage collector](#garbage-collector) | [gate](#gate) | [generated file](#generated-file) | [gengtype](#gengtype) | [gimplification](#gimplification) | [hard register](#hard-register) | [immediate dominator](#immediate-dominator) | [inferior call](#inferior-call) | [insn](#insn) | [interference](#interference) | [live range](#live-range) | [loop](#loop) | [machine description](#machine-description) | [machine mode](#machine-mode) | [middle end](#middle-end) | [mode iterator](#mode-iterator) | [optimization level](#optimization-level) | [out of SSA](#out-of-ssa) | [out of tree build](#out-of-tree-build) | [output template](#output-template) | [param](#param) | [pass](#pass) | [pass manager](#pass-manager) | [pass positioning](#pass-positioning) | [phi node](#phi-node) | [plugin](#plugin) | [plugin ABI](#plugin-abi) | [plugin event](#plugin-event) | [poly_int](#poly_int) | [port](#port) | [pretty printer](#pretty-printer) | [pseudo register](#pseudo-register) | [pseudo-event](#pseudo-event) | [register allocation](#register-allocation) | [register class](#register-class) | [register pressure](#register-pressure) | [section](#section) | [spec](#spec) | [spec function](#spec-function) | [specs file](#specs-file) | [spill](#spill) | [stage comparison](#stage-comparison) | [stamp file](#stamp-file) | [sum file](#sum-file) | [target hook](#target-hook) | [target triple](#target-triple) | [temporary](#temporary) | [three address form](#three-address-form) | [torture options](#torture-options) | [tree](#tree) | [use](#use) | [wide_int](#wide_int) +[DejaGnu](#dejagnu) | [GENERIC](#generic) | [GIMPLE](#gimple) | [IRA](#ira) | [LRA](#lra) | [RTL](#rtl) | [RTX](#rtx) | [SSA](#ssa) | [SSA name](#ssa-name) | [TODO flags](#todo-flags) | [allocno](#allocno) | [alternative](#alternative) | [assembler directive](#assembler-directive) | [back end](#back-end) | [basic block](#basic-block) | [blue paint](#blue-paint) | [bootstrap](#bootstrap) | [bubbling](#bubbling) | [build config](#build-config) | [cc1](#cc1) | [checking build](#checking-build) | [collect2](#collect2) | [compiler table](#compiler-table) | [constraint](#constraint) | [control flow graph](#control-flow-graph) | [cross compiler](#cross-compiler) | [current function](#current-function) | [debug counter](#debug-counter) | [default definition](#default-definition) | [define_insn](#define_insn) | [definition](#definition) | [directive](#directive) | [dominance](#dominance) | [driver](#driver) | [dump file](#dump-file) | [edge](#edge) | [effective target](#effective-target) | [excess errors](#excess-errors) | [expand](#expand) | [final](#final) | [front end](#front-end) | [garbage collector](#garbage-collector) | [gate](#gate) | [generated file](#generated-file) | [gengtype](#gengtype) | [gimplification](#gimplification) | [hard register](#hard-register) | [immediate dominator](#immediate-dominator) | [include guard](#include-guard) | [inferior call](#inferior-call) | [insn](#insn) | [interference](#interference) | [line marker](#line-marker) | [live range](#live-range) | [loop](#loop) | [machine description](#machine-description) | [machine mode](#machine-mode) | [middle end](#middle-end) | [mode iterator](#mode-iterator) | [optimization level](#optimization-level) | [out of SSA](#out-of-ssa) | [out of tree build](#out-of-tree-build) | [output template](#output-template) | [param](#param) | [pass](#pass) | [pass manager](#pass-manager) | [pass positioning](#pass-positioning) | [phi node](#phi-node) | [plugin](#plugin) | [plugin ABI](#plugin-abi) | [plugin event](#plugin-event) | [poly_int](#poly_int) | [port](#port) | [preprocessor](#preprocessor) | [pretty printer](#pretty-printer) | [pseudo register](#pseudo-register) | [pseudo-event](#pseudo-event) | [register allocation](#register-allocation) | [register class](#register-class) | [register pressure](#register-pressure) | [section](#section) | [spec](#spec) | [spec function](#spec-function) | [specs file](#specs-file) | [spill](#spill) | [stage comparison](#stage-comparison) | [stamp file](#stamp-file) | [sum file](#sum-file) | [target hook](#target-hook) | [target triple](#target-triple) | [temporary](#temporary) | [three address form](#three-address-form) | [token](#token) | [token pasting](#token-pasting) | [torture options](#torture-options) | [translation unit](#translation-unit) | [tree](#tree) | [use](#use) | [wide_int](#wide_int) ## Reading the source @@ -222,6 +222,66 @@ It is generated, mostly. A target is described by a `.md` file full of patterns Taught in T01. See also [RTL](#rtl), [middle end](#middle-end). +## Before the parser + +The first program in the chain, and the one whose output every other lesson quietly assumes. F02 is the lesson. + +### preprocessor + +**The phase that runs before the parser, and the only one that works in tokens without types.** + +It is not a separate program in a normal compilation. `cc1` contains libcpp and calls it for each token, so `gcc -E` is the same code with the output printed instead of parsed. The thing worth unlearning is that it edits text. It lexes your file into tokens, works on tokens, and prints tokens back out, and the printing step has to insert whitespace that was in no input file to stop two of them lexing as one. Everything people find surprising about macros follows from that. + +Also written libcpp, `cpp`, `-E`. Taught in F02. See also [token](#token), [translation unit](#translation-unit), [cc1](#cc1). In the source: [`libcpp/init.cc:589@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/libcpp/init.cc#L589). + +### token + +**One lexical unit, with a type, a location and some flags. What the preprocessor deals in.** + +A `cpp_token` is thirty two bytes on a 64-bit host: a location, a type from a list of about a hundred, a flag word, and a union holding the spelling. `PREV_WHITE` in those flags is the one to know, because it is where the space before a token lives; the space is a property of the token after it rather than a character in a buffer. A macro expanding to nothing can therefore still leave a space behind, and two tokens that arrive next to each other can still be printed apart. + +Also written `cpp_token`, `PREV_WHITE`. Taught in F02. See also [preprocessor](#preprocessor), [token pasting](#token-pasting). In the source: [`libcpp/include/cpplib.h:261@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/libcpp/include/cpplib.h#L261). + +### translation unit + +**One source file with every #include pasted in and every macro expanded. What the parser sees.** + +It is the unit C is defined in terms of, and it is much larger than the file you wrote. One `#include ` opens dozens of files, so a hundred line program is routinely tens of thousands of lines by the time the parser starts. This is the reason a compiler feels slow on small files, the reason a macro defined in one header can break a declaration in another, and the reason `gcc -E` is the first thing to run when a build error names a line you cannot find. + +Also written TU. Taught in F02. See also [preprocessor](#preprocessor), [include guard](#include-guard). + +### line marker + +**A `# 42 "file.h" 2 3 4` line in preprocessed output, saying where the following text came from.** + +Not a comment and not a directive. It is how the preprocessor hands the parser back the line numbers it destroyed by pasting files together, which is what makes an error inside a header point at the header. The digits after the filename are flags: 1 means entering a file, 2 means returning to one, 3 means a system header where warnings are suppressed, and 4 means the contents are to be wrapped in `extern "C"`. Flag 3 is the reason a warning in your code disappears when you move the same code into `/usr/include`. + +Also written `#line`, linemarker. Taught in F02. See also [preprocessor](#preprocessor), [translation unit](#translation-unit). In the source: [`gcc/c-family/c-ppoutput.cc:618@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/gcc/c-family/c-ppoutput.cc#L618). + +### include guard + +**The `#ifndef NAME / #define NAME / #endif` wrapper that stops a header being read twice.** + +The interesting part is not the idiom, it is that libcpp recognises it. When a file's entire token stream is one conditional controlled by a macro, the file is remembered along with that macro's name, and the next `#include` of it is skipped without opening the file at all. The recognition is exact: one declaration after the `#endif` and the optimization is off, though a comment there costs nothing, because the check is over tokens and a comment is not one. + +Also written multiple inclusion guard, `cmacro`, `#pragma once`. Taught in F02. See also [preprocessor](#preprocessor), [translation unit](#translation-unit). In the source: [`libcpp/files.cc:858@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/libcpp/files.cc#L858). + +### token pasting + +**Two things that mean opposite things: the `##` operator, and the accident it is named after.** + +`a ## b` is the operator, and it makes two tokens into one before the result is scanned for macros, which is why `CAT(PLUS, PLUS)` gives you the identifier `PLUSPLUS` and not `++`. The accident is what `cpp_avoid_paste` exists to prevent: when the preprocessor prints two adjacent tokens that would lex back as one, it puts a space between them that was in no input file. Both are the same fact seen from two sides, which is that the preprocessor's output is tokens and its printed form is a lossy rendering of them. + +Also written `##`, `cpp_avoid_paste`. Taught in F02. See also [token](#token), [preprocessor](#preprocessor). In the source: [`libcpp/lex.cc:4728@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/libcpp/lex.cc#L4728). + +### blue paint + +**The mark that stops a macro expanding inside its own expansion, so `#define foo foo + 1` terminates.** + +While a macro is being expanded, its name is disabled; any occurrence of it in the result is flagged `NO_EXPAND` and stays that way forever, even if it is later passed somewhere the macro is not being expanded. The standard's rule and libcpp's implementation are the reason `#define A B` and `#define B A` produce `A` rather than a hang. The name is from a 1980s comp.std.c thread about painting the identifier blue so it cannot be expanded again, and the source uses it. + +Also written `NO_EXPAND`, painted blue, self-reference. Taught in F02. See also [preprocessor](#preprocessor), [token](#token). In the source: [`libcpp/macro.cc:1590@releases/gcc-16.2.0`](https://github.com/gcc-mirror/gcc/blob/releases/gcc-16.2.0/libcpp/macro.cc#L1590). + ## The four shapes a function takes The same function, written down four different ways on its way to assembly. T02, T03 and T07 are the lessons. diff --git a/README.md b/README.md index 9a43bd6..84afd59 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,9 @@ Lessons do not invent a fresh example each time either. There are three programs | B04 | [Forty thousand tests, and how to run one of them](https://github.com/tamnd/gcc-internals/blob/main/lessons/b04-the-test-suite/b04.ipynb) | The GCC test suite taken apart: what a directive is, why the command line is not what the file says, the subtractive rule that makes a test fail for output nobody asked about, the six compilations every torture test costs, how to run one file without running the other thirty five thousand, and the one question worth asking of a .sum | M2 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/b04-the-test-suite/b04.ipynb) | | B05 | [Sixty lines of C++, and you are inside the compiler](https://github.com/tamnd/gcc-internals/blob/main/lessons/b05-the-plugin/b05.ipynb) | GCC's plugin mechanism from the outside in: the three things a plugin has to have, the three ways it is refused, what an event actually is, a GIMPLE pass of your own inserted after ssa with its own dump file, switching one of GCC's passes off from outside and watching the assembly move, and why the thing you are writing against is not an API | M2 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/b05-the-plugin/b05.ipynb) | | F01 | [The driver is an interpreter](https://github.com/tamnd/gcc-internals/blob/main/lessons/f01-the-spec-language/f01.ipynb) | That `gcc -dumpspecs` prints a program, in a language with conditionals and function calls, which the driver interprets to decide what to run; how to read it; and four text files that change what your compiler does without patching or rebuilding it | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/f01-the-spec-language/f01.ipynb) | +| F02 | [The preprocessor is not a text editor](https://github.com/tamnd/gcc-internals/blob/main/lessons/f02-tokens-not-text/f02.ipynb) | That the preprocessor lexes your file into tokens before it does anything else, and that its printed output is a rendering of those tokens rather than the tokens themselves; the space GCC inserts that is in no input file; the four hundred macros you did not write; and why one #include of stdio.h opens thirty eight files | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/f02-tokens-not-text/f02.ipynb) | -18 of 96 written. +19 of 96 written. This table is generated from the lessons, by the same command that builds them, so it cannot list a lesson that does not exist or miss one that does. T05 is the pilot and it is deliberately in the middle of Part I rather than at the start, because everything the course promises has to be true of a hard lesson before it is worth writing the easy ones. diff --git a/blueprints/BP-CPP.md b/blueprints/BP-CPP.md new file mode 100644 index 0000000..530d2d8 --- /dev/null +++ b/blueprints/BP-CPP.md @@ -0,0 +1,607 @@ +# BP-CPP, the preprocessor + +**Status:** partial +**Applies to:** GCC 16.2.0 (tag `releases/gcc-16.2.0`) +**Target-dependent:** yes +**Generated sections:** none +**Last verified:** 2026-09-06 against `releases/gcc-16.2.0` + +This document specifies libcpp, the library that turns a source file into a stream of preprocessing tokens, and the client in `gcc/c-family/c-ppoutput.cc` that prints that stream when you ask for `-E`. The token, the token type table, the hash node and the macro are specified field by field. Lexing, macro expansion, argument prescan, stringification, pasting, the disabling rule, the multiple include optimization and the spacing rule the printer applies are specified as algorithms. Traditional mode, modules and header units, precompiled headers, `#embed`, character set conversion and the `#if` expression evaluator are named and not specified, and each place that stops short says so. Nothing here is generated, because libcpp keeps its tables in C macros rather than in `.def` files a script could read without a C parser. What exists instead is `gxray.cpp`, a reader for recorded preprocessor output, with tests that compare its table of paste-avoiding pairs against the case labels of `cpp_avoid_paste` in the pinned tree, so a GCC that grows a pair fails the build rather than making a paragraph quietly false. + +## 1. Purpose and scope + +The preprocessor is not a program. It is a library, libcpp, linked into `cc1` and into every other C family front end, and `gcc -E` does not start a separate process: it runs the same `cc1` with a flag that makes it stop after preprocessing and print. A reader who goes looking for a `cpp` binary in the chain will not find one, which is what T01 observes from the outside and this document explains from the inside. + +The library's contract with its client is one function. `cpp_get_token` at `libcpp/macro.cc:3265@releases/gcc-16.2.0` returns the next preprocessing token, and everything else libcpp does happens behind it: opening files, expanding macros, evaluating conditionals, skipping dead branches, and maintaining the line map that says where each token came from. The client either builds a parse tree from those tokens, which is what `cc1` does, or prints them, which is what `-E` does. + +**What this document covers.** The token and its flags. The token type table. How a file becomes tokens. How a macro is defined, invoked, expanded, prescanned, stringified and pasted, and why an expansion cannot recurse. The include stack, the multiple include optimization, and `#pragma once`. The line map far enough to explain a line marker. The `-E` printer, including the rule that decides where a space goes. + +**What it does not cover.** Traditional mode, which is a second preprocessor in `libcpp/traditional.cc` with its own lexer and its own macro expander, reached with `-traditional-cpp`. C++ modules and header units. Precompiled headers. `#embed`, which is new in C23 and large. Character set conversion, universal character names and the input charset machinery. The `#if` expression evaluator in `libcpp/expr.cc`, except for the one thing it contributes to the include guard state machine. Assertions, the `#assert` family, which GCC marks deprecated in its own directive table. Deferred pragmas, beyond noting where they interrupt the token stream. + +**Position in the pipeline.** First. Every other document in this book describes something that happens to tokens this one produced. + +**Inputs and outputs as properties.** None. The `PROP_*` flags describe IR held by the middle end, and libcpp holds none. Its input is a file and its output is a token stream. + +## 2. Data structures + +### 2.1 The token + +`cpp_token` at `libcpp/include/cpplib.h:265@releases/gcc-16.2.0`, and its own comment at `libcpp/include/cpplib.h:261@releases/gcc-16.2.0` says it occupies 32 bytes on a 64-bit host. + +| Field | Type | Meaning | +|---|---|---| +| `src_loc` | `location_t` | a key into the line map, not a line number | +| `type` | `cpp_ttype` in 8 bits | which of the 90 kinds of token this is | +| `flags` | `unsigned short` | the 13 flags below | +| `val` | union | the payload, discriminated by `type` | + +The union has six members and the discriminator is a function, `cpp_token_val_index` at `libcpp/include/cpplib.h:297@releases/gcc-16.2.0`, rather than a field. An identifier carries a `cpp_hashnode *`, a number or string carries a `cpp_string`, a macro argument carries an index, a deferred pragma carries a cookie, and a padding token carries a pointer to the token whose whitespace it is standing in for. + +There are 13 flags, at `libcpp/include/cpplib.h:199@releases/gcc-16.2.0`, and they are the part a reader of preprocessed output needs, because three of them are the whole reason the output looks the way it does. + +| Flag | Bit | Meaning | +|---|---|---| +| `PREV_WHITE` | 0 | there was whitespace before this token in the file | +| `DIGRAPH` | 1 | it was written as a digraph, so `%:` rather than `#` | +| `STRINGIFY_ARG` | 2 | a macro parameter with `#` in front of it | +| `PASTE_LEFT` | 3 | this token is the left operand of a `##` | +| `NAMED_OP` | 4 | a C++ named operator, so `and` rather than `&&` | +| `PREV_FALLTHROUGH` | 5 | preceded by a fallthrough comment | +| `DECIMAL_INT` | 6 | a decimal integer, and set by the front end rather than by libcpp | +| `PURE_ZERO` | 7 | a single `0` digit, and aliased twice as `COLON_SCOPE` and `NO_DOT_COLON` | +| `SP_DIGRAPH` | 8 | the `#` or `##` in a definition was a digraph | +| `SP_PREV_WHITE` | 9 | whitespace before a `##` in a definition | +| `NO_EXPAND` | 10 | never macro expand this token, whatever the table says | +| `PRAGMA_OP` | 11 | came from `_Pragma` | +| `BOL` | 12 | first token on a line | + +Two of those thirteen bits are not libcpp's. `DECIMAL_INT` is set in `gcc/c-family/c-lex.cc`, and `PURE_ZERO` is read by the C++ front end, which is what it means for a token to be a shared structure rather than a private one. + +`PREV_WHITE` is one bit and it is the only record of the spacing in the original file. A token does not know how many spaces were in front of it, or whether they were tabs, or whether there was a comment there. The printer reconstructs a plausible spacing from this bit and from the rules in section 3.8, and the reconstruction is not the input. + +### 2.2 The token types + +`TTYPE_TABLE` at `libcpp/include/cpplib.h:54@releases/gcc-16.2.0` is one C macro with **90** entries, expanded three times in the whole compiler: into `enum cpp_ttype` at `libcpp/include/cpplib.h:161@releases/gcc-16.2.0`, into the spelling table `token_spellings` at `libcpp/lex.cc:46@releases/gcc-16.2.0`, and into a table of names for the C++ parser's own debug printer at `gcc/cp/parser.cc:1677@releases/gcc-16.2.0`. **56** entries are punctuation, written `OP(name, spelling)`, and **34** are everything else, written `TK(name, category)`. + +The order is load bearing and the comment above the table at `libcpp/include/cpplib.h:43@releases/gcc-16.2.0` says so. Four names are positions rather than types: + +| Name | Equals | Why it exists | +|---|---|---| +| `CPP_LAST_EQ` | `CPP_LSHIFT` | everything at or below it can be followed by `=` to make another token | +| `CPP_FIRST_DIGRAPH` | `CPP_HASH` | the digraph spellings are a contiguous run starting here | +| `CPP_LAST_PUNCTUATOR` | `CPP_ATSIGN` | above this, a token has a payload rather than a fixed spelling | +| `CPP_LAST_CPP_OP` | `CPP_LESS_EQ` | above this, a token cannot appear in a `#if` expression | + +Every type has a spelling category, from `enum spell_type` at `libcpp/lex.cc:27@releases/gcc-16.2.0`: `SPELL_OPERATOR` for a fixed string, `SPELL_IDENT` for a hash node's name, `SPELL_LITERAL` for a stored string, and `SPELL_NONE` for the types that cannot be printed at all. The category is what `cpp_output_token` at `libcpp/lex.cc:4637@releases/gcc-16.2.0` switches on. + +### 2.3 The padding token + +`CPP_PADDING` at `libcpp/include/cpplib.h:157@releases/gcc-16.2.0` is the last entry in the table and the only one that is not a preprocessing token in the language's sense. It carries no text. It exists so that the token stream can say "there was a macro boundary here" at a point where the language says nothing happened, and its `val.source` points at the token whose `PREV_WHITE` should be consulted. + +A macro that expands to nothing does not expand to nothing. It expands to a padding token, produced by `padding_token` at `libcpp/macro.cc:2454@releases/gcc-16.2.0`, and the printer's response to that padding is the space in section 5.3 that appears in no input file. + +### 2.4 The hash node + +`cpp_hashnode` at `libcpp/include/cpplib.h:1069@releases/gcc-16.2.0` is one identifier, interned. Every occurrence of a name anywhere in the translation unit points at the same node, which is why testing whether a name is a macro is a pointer comparison rather than a string comparison. + +| Field | Bits | Meaning | +|---|---|---| +| `ident` | | the interned string, from libiberty's hash table | +| `is_directive` | 1 | this name is a directive name | +| `directive_index` | 7 | which one, or a `NODE_OPERATOR` code | +| `rid_code` | 8 | the front end's keyword code, unused by libcpp | +| `flags` | 9 | the `NODE_*` flags | +| `type` | 2 | `enum node_type` | +| `deferred` | 32 | a cookie for lazily defined macros | +| `value` | | a union discriminated by `type` | + +`enum node_type` at `libcpp/include/cpplib.h:1015@releases/gcc-16.2.0` has four values, and the interesting one is that a macro is not a separate kind of object. `NT_VOID` is an ordinary identifier, `NT_USER_MACRO` has a `cpp_macro *` in `value`, `NT_BUILTIN_MACRO` has a `cpp_builtin_type` in `value` and no body at all, and `NT_MACRO_ARG` is what a parameter name becomes while its own definition is being read. + +Of the nine `NODE_*` flags at `libcpp/include/cpplib.h:1004@releases/gcc-16.2.0`, one is an algorithm rather than a property. `NODE_DISABLED` at `libcpp/include/cpplib.h:1008@releases/gcc-16.2.0` is set on a macro while its own expansion is being rescanned, and section 3.6 is the whole story. + +### 2.5 The macro + +`cpp_macro` at `libcpp/include/cpplib.h:930@releases/gcc-16.2.0` is a header with the replacement list as a trailing array, so one allocation holds a definition. + +| Field | Meaning | +|---|---| +| `parm.params` | the parameter names, as hash nodes, or the assertion chain | +| `line` | where it was defined, for the "defined here" note | +| `count` | how many tokens are in the body | +| `paramc` | how many parameters | +| `lazy` | the value is supplied by the client on first use | +| `kind` | ISO, traditional or assertion, in 2 bits | +| `fun_like` | whether an invocation needs a bracket | +| `variadic` | whether the last parameter is `...` | +| `syshdr` | defined in a system header, which suppresses warnings | +| `used` | expanded or tested at least once, for `-Wunused-macros` | +| `extra_tokens` | trailing `CPP_PASTE` tokens are present for redefinition checking | +| `imported_p` | came from a C++20 header unit | +| `exp.tokens` | the replacement list, `count` of them | + +`fun_like` is the field behind the rule most people learn by accident: a function-like macro named without a following `(` is not an invocation and is left alone. Section 3.3 is where that is decided. + +### 2.6 The built-in macros + +`builtin_array` at `libcpp/init.cc:449@releases/gcc-16.2.0` holds **20** names whose value is computed by a C function rather than stored as tokens, and `enum cpp_builtin_type` at `libcpp/include/cpplib.h:1026@releases/gcc-16.2.0` holds the **19** codes they map to, two names sharing `BT_HAS_ATTRIBUTE`. + +```text +__TIMESTAMP__ __TIME__ __DATE__ __FILE__ +__FILE_NAME__ __BASE_FILE__ __LINE__ __INCLUDE_LEVEL__ +__COUNTER__ __has_attribute __has_c_attribute __has_cpp_attribute +__has_builtin __has_include __has_include_next __has_embed +__has_feature __has_extension _Pragma __STDC__ +``` + +None of these has a body, so none of them can be printed by a dump of the macro table, and section 5.2 records that 19 of the 20 are absent from `-dM` output. The exception is `__STDC__`, and the reason is one line: `cpp_init_builtins` at `libcpp/init.cc:589@releases/gcc-16.2.0` installs the array through `cpp_init_special_builtins` at `libcpp/init.cc:539@releases/gcc-16.2.0` and then, at `libcpp/init.cc:596@releases/gcc-16.2.0`, defines `__STDC__` a second time the ordinary way, with a value. The ordinary definition is what the dump can see. + +The other names in the table a reader will find with `-dM` come from two places that are not libcpp at all. `cpp_init_builtins` goes on to define the language version macros the ordinary way too, `__cplusplus` at `libcpp/init.cc:606@releases/gcc-16.2.0` and `__STDC_VERSION__` at `libcpp/init.cc:639@releases/gcc-16.2.0`, one arm of a chain of `else if` on the selected standard. Everything about the machine, which is most of the table, is defined by the front end and the target through `c_cpp_builtins` in `gcc/c-family/c-cppbuiltin.cc` and the target's `TARGET_CPU_CPP_BUILTINS` hook. That split is why the count in section 5.1 is a fact about a target rather than about a compiler version. + +### 2.7 The file + +`_cpp_file` at `libcpp/files.cc:54@releases/gcc-16.2.0` is a file the preprocessor has looked at, whether or not it read it. Three fields carry the whole include story. + +| Field | Meaning | +|---|---| +| `cmacro` | the macro whose being defined means this file need not be read again | +| `once_only` | `#pragma once` or `#import`, so it is never read again regardless | +| `stack_count` | how many times this file has been pushed on the buffer stack | + +`cmacro` at `libcpp/files.cc:80@releases/gcc-16.2.0` is `nothing` until the file has been read to the end at least once, because working out the guard requires reading the file. The first inclusion of a guarded header therefore costs a full read and a full lex. The saving is on the second and later inclusions, and section 5.5 measures it. + +### 2.8 The directives + +`DIRECTIVE_TABLE` at `libcpp/directives.cc:151@releases/gcc-16.2.0` holds **22** directives, each with a handler, an origin and a set of flags, and expands into a prototype list, an enum and an array. The origin is one of `KANDR`, `STDC89`, `STDC23` or `EXTENSION`, which is how `-pedantic` knows what to complain about. + +Two of the flags matter outside `directives.cc`. `IF_COND` marks four directives, and it is misnamed: three of them open a conditional, `#ifdef`, `#ifndef` and `#if`, and the fourth is `#define`. What the flag really means is that this directive will look after the include guard state itself, and section 3.7 says what that state is. `#define` carries it because `do_define` reads `mi_valid` at `libcpp/directives.cc:700@releases/gcc-16.2.0` before clearing it at `libcpp/directives.cc:720@releases/gcc-16.2.0`, and what it reads it for is the check behind `-Wheader-guard`. `EXPAND` marks the directives whose line is macro expanded before it is read, which is `#include`, `#if`, `#elif`, `#line`, `#include_next`, `#import` and `#embed`, and is why `#include HEADER` works and `#ifdef FOO` does not expand `FOO`. + +## 3. Algorithms + +### 3.1 From bytes to a line of tokens + +`_cpp_clean_line` at `libcpp/lex.cc:877@releases/gcc-16.2.0` runs first on every logical line. It removes trailing whitespace, joins lines ending in a backslash, and normalizes the line ending, recording each thing it did as a note. `_cpp_process_line_notes` at `libcpp/lex.cc:1082@releases/gcc-16.2.0` replays those notes later so that a diagnostic can point at the column in the file the user wrote rather than the column in the line libcpp made. + +This is where translation phases 1 to 3 of the C standard happen, and libcpp does not run them as separate passes over the whole file. Trigraph replacement, line splicing and comment removal all happen a line at a time as the lexer needs them, which is observable: a `\` at the end of a line inside a `//` comment continues the comment, because splicing happened before the comment was recognized. + +`_cpp_lex_direct` at `libcpp/lex.cc:3888@releases/gcc-16.2.0` produces one token. `_cpp_lex_token` at `libcpp/lex.cc:3725@releases/gcc-16.2.0` wraps it and is the one the rest of the library calls, because it is the layer that handles directives, skipped conditional branches and the end of a file. + +```text +_cpp_lex_token(pfile): + loop + token = _cpp_lex_direct(pfile) + if token.flags has BOL and token is '#' and not in a directive + if _cpp_handle_directive(pfile, indented) + continue # the directive consumed the line + if in a directive or a deferred pragma + break # never skip inside one + pfile.mi_valid = false # a token outside a directive kills the guard + if not skipping or token is CPP_EOF + break + return token +``` + +The assignment at `libcpp/lex.cc:3796@releases/gcc-16.2.0` is one line of the include guard state machine and is placed here rather than in `directives.cc` because this is the only place that sees a token which is not part of a directive. + +### 3.2 Getting a token + +`cpp_get_token_1` at `libcpp/macro.cc:3006@releases/gcc-16.2.0` is the loop everything above libcpp turns. Its state is a stack of contexts: the base context is the file, and each macro under expansion pushes a context holding the tokens it has yet to hand out. + +```text +cpp_get_token_1(pfile) -> Token + complexity: O(1) amortized, unbounded in the worst case for one call + + loop + context = pfile.context + if context is the base context + result = _cpp_lex_token(pfile) + else if context has tokens left + result = next token from context + if result.flags has PASTE_LEFT + paste_all_tokens(pfile, result) # section 3.5 + return padding_token(pfile, result) + else + pop the context + return the avoid_paste token # a padding token + + if result.type != CPP_NAME + break + node = result.val.node + if node.type == NT_VOID or result.flags has NO_EXPAND + break + if node.flags has NODE_DISABLED + result = a copy of result with NO_EXPAND set # section 3.6 + break + if pfile.state.prevent_expansion + break + if enter_macro_context(pfile, node, result) # section 3.3 + return padding_token(pfile, result) + return result +``` + +One call can do an unbounded amount of work, because entering a macro context may collect arguments, which reads more tokens, which may open a file. The complexity worth stating is the other one: the total work over a translation unit is linear in the number of tokens produced, and a macro whose expansion is quadratic is quadratic because it produces quadratically many tokens, not because any step here is superlinear. + +Two of the returns hand back a padding token rather than the thing the caller asked for. That is the mechanism by which a macro boundary survives into the output. + +The block above leaves out three things the real loop does, all of them in the same place, between recognizing a name and expanding it. A macro the client promised to supply later is fetched through `cpp_get_deferred_macro` at `libcpp/macro.cc:3066@releases/gcc-16.2.0`, which is how a C++ module's macros arrive. A macro flagged `NODE_CONDITIONAL` asks the client whether to expand it at all, at `libcpp/macro.cc:3097@releases/gcc-16.2.0`. And inside a directive every one of the returns above becomes a `continue` instead, because a directive line has no room for padding. None of the three changes what happens to an ordinary macro in an ordinary C file, which is what sections 5.3 and 5.4 record. + +### 3.3 Entering a macro + +`enter_macro_context` at `libcpp/macro.cc:1527@releases/gcc-16.2.0` decides whether this occurrence of a macro name is an invocation, and if it is, builds the replacement list and pushes it as a context. + +```text +enter_macro_context(pfile, node, result) -> 0, 1 or 2 + complexity: O(body + total argument length), plus prescanning each argument + + pfile.mi_valid = false # a macro invalidates the guard + + if node is a user macro + macro = node.value.macro + if macro.fun_like + args = funlike_invocation_p(pfile, node) + if args is nothing + return 0 # the name, alone, is not an invocation + if macro.paramc > 0 + replace_args(pfile, node, macro, args) # pushes the context itself + node.flags = node.flags or NODE_DISABLED # section 3.6 + if macro.paramc == 0 + push macro.exp.tokens as a context + if any deferred pragma turned up in an argument + push those tokens as a further context + return 2 + return 1 + + return builtin_macro(pfile, node, ...) # computes a value and pushes it +``` + +`funlike_invocation_p` at `libcpp/macro.cc:1463@releases/gcc-16.2.0` reads forward past any number of padding tokens, and if what it finds is not `(` it puts the token back with `_cpp_backup_tokens` at `libcpp/macro.cc:3379@releases/gcc-16.2.0` and reports no invocation. Reading forward is the reason a function-like macro at the very end of a file does not hang: the lookahead hits `CPP_EOF` and backs up. + +`collect_args` at `libcpp/macro.cc:1249@releases/gcc-16.2.0` reads the arguments, counting bracket depth and treating a comma at depth zero as a separator. A comma inside a nested `(...)` is part of an argument, and a comma inside `[...]` or `{...}` is not, which is why a macro invoked with a compound literal or a template argument list needs extra brackets. It also checks the argument count, calling `_cpp_arguments_ok` at `libcpp/macro.cc:1431@releases/gcc-16.2.0` before it returns, so a wrong count reaches `enter_macro_context` as an empty answer indistinguishable from a name with no bracket after it, and the name is printed as itself. + +### 3.4 Prescan and stringification + +`replace_args` at `libcpp/macro.cc:1987@releases/gcc-16.2.0` builds the replacement list, and the order it does two things in is the answer to the most common macro question there is. + +```text +replace_args(pfile, node, macro, args) -> sequence of Token + complexity: O(body + total expanded argument length) + + for each parameter i used in the body + if the body uses #i + args[i].stringified = stringify_arg(pfile, args[i].raw) + if the body uses i without # or ## next to it + args[i].expanded = expand_arg(pfile, args[i]) # the prescan + # if the body only uses i next to # or ##, neither is computed + + for each token t in the body + if t is a macro argument + append the stringified, expanded or raw form, as the body demands + else + append t +``` + +`expand_arg` at `libcpp/macro.cc:2768@releases/gcc-16.2.0` is the prescan: an argument is fully macro expanded before it is substituted, unless the parameter it is bound to is an operand of `#` or `##`. `stringify_arg` at `libcpp/macro.cc:931@releases/gcc-16.2.0` uses the raw form, spelling each token and separating them by one space where `PREV_WHITE` says there was whitespace. + +That exception is why `#define STR(x) #x` gives the parameter's spelling and the two step `#define XSTR(x) STR(x)` gives its expansion. In `XSTR(PLUS)` the parameter of `XSTR` is not next to a `#`, so it is prescanned to `+`, and `STR` then stringifies the token it was handed. Section 5.4 records both. + +### 3.5 Pasting + +`paste_all_tokens` at `libcpp/macro.cc:1098@releases/gcc-16.2.0` handles a run of `##` operators left to right, and `paste_tokens` at `libcpp/macro.cc:1029@releases/gcc-16.2.0` does one paste. The implementation is the specification here, because it is not what most people picture. + +```text +paste_tokens(pfile, plhs, rhs) -> ok or error + complexity: O(length of the two spellings) + + buf = spell(plhs) followed by spell(rhs), then a newline + if plhs is '/' and rhs is not '=' + insert a space between them # or the buffer opens a comment + push buf as a buffer and lex one token from it + if the buffer is not exhausted + the paste failed + clear PASTE_LEFT on the left token and put both back + error "pasting X and Y does not give a valid preprocessing token" + return the lexed token +``` + +Pasting is spelling the two tokens, running the lexer over the result, and requiring that the lexer consume all of it. That is why `##` cannot make `++` out of two macros that each expand to `+`: the operands of `##` are not prescanned, so the two tokens being pasted are the identifiers `PLUS` and `PLUS`, and the lexer reads `PLUSPLUS` as one identifier. The paste succeeds and produces the wrong thing, which is worse than failing. Section 5.4 records it. + +The failure message is at `libcpp/macro.cc:1076@releases/gcc-16.2.0` and is an error rather than a warning for every language except assembler. + +### 3.6 Why an expansion does not recurse + +The standard says a macro name found while rescanning its own replacement list is not expanded, and that thereafter it is never expanded again anywhere, even by a later scan. GCC implements that in two flags. + +```text +on entering a macro context: node.flags |= NODE_DISABLED +on leaving it (_cpp_pop_context): node.flags &= ~NODE_DISABLED +on meeting a disabled name: hand back a copy with NO_EXPAND set +``` + +The first is at `libcpp/macro.cc:1590@releases/gcc-16.2.0` and the third is in `cpp_get_token_1` at `libcpp/macro.cc:3129@releases/gcc-16.2.0`, which allocates a temporary token with `_cpp_temp_token` at `libcpp/lex.cc:3460@releases/gcc-16.2.0` rather than modifying the one in the macro body, because the body is shared by every invocation. + +`NODE_DISABLED` alone would not be enough. It is cleared when the context pops, so a name that survived into the output while disabled would be expandable again by the time somebody rescanned it. `NO_EXPAND` is on the token rather than on the node, so it travels with the token forever. The two together are what the standard calls painting the identifier blue. + +The consequence a reader can check: `#define foo foo + 1` terminates and produces `foo + 1`, and a pair of macros that name each other produces one of the two names unchanged. Section 5.4 records both. + +### 3.7 The multiple include optimization + +A header wrapped in `#ifndef GUARD / #define GUARD / ... / #endif` is skipped on its second inclusion without being opened. Getting that right requires proving that the conditional wraps the entire file, and libcpp proves it with three variables and four assignments rather than with a scan. + +```text +state: mi_valid is the file still a candidate + mi_cmacro the controlling macro, once one is known + +on stacking a file mi_valid = true, mi_cmacro = nothing +in _cpp_handle_directive if the directive does not have IF_COND: mi_valid = false +in push_conditional ifs.mi_cmacro = cmacro if (mi_valid and mi_cmacro == nothing) + else nothing +in do_define mi_valid = false # after reading it, for -Wheader-guard +in _cpp_lex_token mi_valid = false # any token outside a directive +in enter_macro_context mi_valid = false # any macro invocation +in do_else and do_elif ifs.mi_cmacro = nothing # a guard has no else branch +in do_endif if this is the outermost #if and ifs.mi_cmacro is set + mi_valid = true, mi_cmacro = ifs.mi_cmacro +in _cpp_pop_file_buffer if mi_valid: file.cmacro = mi_cmacro + mi_valid = false # for the file that included this one +``` + +Nine places touch two variables, and nothing anywhere scans the file. The clearing in `_cpp_handle_directive` is at `libcpp/directives.cc:504@releases/gcc-16.2.0`, the two in `do_else` and `do_elif` are at `libcpp/directives.cc:2670@releases/gcc-16.2.0` and `libcpp/directives.cc:2771@releases/gcc-16.2.0`, and the test in `push_conditional` at `libcpp/directives.cc:2843@releases/gcc-16.2.0` carries a comment saying it is effectively a test for top of file, and that is the trick: `mi_valid` starts true and is cleared by the first token or directive that is not the opening conditional, so if it is still true when a conditional opens, nothing preceded that conditional. The assignment in `do_endif` at `libcpp/directives.cc:2807@releases/gcc-16.2.0` sets it back, and the assignment in `_cpp_lex_token` clears it again the moment a token appears after the `#endif`. Whatever survives to `_cpp_pop_file_buffer` at `libcpp/files.cc:2326@releases/gcc-16.2.0` is a guard that covered the whole file. + +The check that uses it is in `is_known_idempotent_file` at `libcpp/files.cc:840@releases/gcc-16.2.0`, three lines at `libcpp/files.cc:858@releases/gcc-16.2.0`: if the file has a `cmacro` and that macro is defined, do not stack the file. + +This is why one declaration after the `#endif` costs the optimization and a comment does not. A comment produces no token. Section 5.5 measures both. + +`#pragma once` reaches the same result by a different and more expensive road. `has_unique_contents` at `libcpp/files.cc:880@releases/gcc-16.2.0` compares the newly read file against every once-only file already seen whose size and modification time match, byte for byte, so that the same header reached through two different paths is recognized. That is a read and a `memcmp` per candidate, where the guard is a pointer test. + +### 3.8 Printing, and where the space comes from + +`preprocess_file` at `gcc/c-family/c-ppoutput.cc:89@releases/gcc-16.2.0` is the `-E` client. It calls `cpp_get_token` in a loop in `scan_translation_unit` at `gcc/c-family/c-ppoutput.cc:400@releases/gcc-16.2.0` and hands each token to `token_streamer::stream` at `gcc/c-family/c-ppoutput.cc:218@releases/gcc-16.2.0`, which is where the output's shape is decided. + +```text +stream(pfile, token, loc) + if token.type == CPP_PADDING + avoid_paste = true + remember the token this padding stands for + return # nothing is printed for padding + + if avoid_paste + if the line changed: emit a line marker and a space + else if the remembered token had PREV_WHITE + or cpp_avoid_paste(pfile, previous printed token, token) + or this is the first token and it is '#' + print one space + else if token.flags has PREV_WHITE and token is not a pragma + print one space + + avoid_paste = false + print the token +``` + +Two independent reasons to print a space, and the first one is not in any input file. When a macro expansion ends, `cpp_get_token_1` hands back a padding token, `avoid_paste` becomes true, and the printer then asks `cpp_avoid_paste` at `libcpp/lex.cc:4728@releases/gcc-16.2.0` whether printing the next token against the previous one would change what the pair lexes as. If it would, a space goes in. + +`cpp_avoid_paste` is a switch on the left token's type with the right token's first character in hand. It opens with a range test, `(int) a <= (int) CPP_LAST_EQ && c == '='`, which is the ordering constraint of section 2.2 being spent, and then has **22** case labels in **17** arms, `CPP_PRAGMA` sharing its answer with `CPP_NAME` and the five string types sharing one between them. Its own comment at `libcpp/lex.cc:4723@releases/gcc-16.2.0` says the function is conservative and will occasionally advise a space where none is needed. + +Line markers are the other half of the printer. `maybe_print_line_1` at `gcc/c-family/c-ppoutput.cc:541@releases/gcc-16.2.0` decides between printing newlines and printing a marker: + +```text +maybe_print_line_1(loc, stream) -> was a marker printed + if the previous line had output on it, end it + if line markers are wanted + and the target line is ahead of the current line by less than 8 + and the file has not changed + print that many newlines + return false + print_line_1(loc, "", stream) + return true +``` + +Eight is a literal in the source at `gcc/c-family/c-ppoutput.cc:557@releases/gcc-16.2.0`. It is the point where a run of blank lines costs more bytes than a marker. + +`print_line_1` at `gcc/c-family/c-ppoutput.cc:592@releases/gcc-16.2.0` writes the marker itself, quoting the filename, and appends the system header flags: + +```text +# LINE "FILE" [FLAGS] +``` + +The flags after the filename are documented at `gcc/doc/cpp.texi:4072@releases/gcc-16.2.0`: `1` entering a file, `2` returning to one, `3` a system header, `4` an implicit `extern "C"` block. `1` and `2` are passed in by the caller. `3` and `4` are computed here from `in_system_header_at`, at `gcc/c-family/c-ppoutput.cc:621@releases/gcc-16.2.0`, and are the reason a marker for a header in `/usr/include` carries a `3` that the header itself never asked for. + +`-P` is one variable, `flag_no_line_commands`, tested at `gcc/c-family/c-ppoutput.cc:555@releases/gcc-16.2.0` and again at `gcc/c-family/c-ppoutput.cc:601@releases/gcc-16.2.0`. With it set, no marker is printed and the output loses the only record of which file each line came from. + +## 4. Invariants + +**I1.** A token's `src_loc` is a key into the line map and is meaningless without it. Nothing in libcpp compares two locations numerically for anything but ordering within one map. +Established by: `linemap_add` at `libcpp/line-map.cc:570@releases/gcc-16.2.0` allocating keys in increasing order. Checked by: nothing. May be broken by: nobody. Worth stating because a `location_t` is an integer and printing it looks like it should mean something. + +**I2.** Every identifier token in the translation unit points at the same `cpp_hashnode` for that spelling. +Established by: the interning hash table. Checked by: nothing. May be broken by: nobody. This is what makes `NODE_DISABLED` a workable mechanism: setting a flag on one node disables a name everywhere at once, which is what the standard asks for. + +**I3.** A macro is disabled for exactly the interval during which its own replacement list is being rescanned, and a name that escapes that interval unexpanded is unexpandable forever. +Established by: `NODE_DISABLED` set at `libcpp/macro.cc:1590@releases/gcc-16.2.0` and cleared in `_cpp_pop_context` at `libcpp/macro.cc:2856@releases/gcc-16.2.0`, and `NO_EXPAND` set at `libcpp/macro.cc:3131@releases/gcc-16.2.0`. Checked by: nothing. May be broken by: nobody. Both halves are required, and section 3.6 says why one is not enough. + +**I4.** The operands of `#` and `##` are never macro expanded, and every other use of a parameter is fully macro expanded before substitution. +Established by: `replace_args` at `libcpp/macro.cc:1987@releases/gcc-16.2.0` computing the expanded form only for parameters that need it. Checked by: nothing. May be broken by: nobody. This is the invariant the two step stringify idiom exists to work around. + +**I5.** A file with a controlling macro is not opened again while that macro is defined, and `cmacro` is set only for a conditional that covered the whole file. +Established by: the state machine of section 3.7. Checked by: nothing, and there is no assertion anywhere that a file skipped this way would in fact have produced no tokens. May be broken by: `#undef` of the guard macro, which makes the file readable again and is a supported thing to do. + +**I6.** `cpp_avoid_paste` may return true when no space is needed, and may not return false when one is. +Established by: the comment at `libcpp/lex.cc:4723@releases/gcc-16.2.0` stating the first half, and by the switch covering every left-hand type that can begin a longer token. Checked by: `tests/test_cpp.py`, which compares the case labels in the pinned tree against a table of witness pairs and fails when GCC grows a case. May be broken by: a new token type added without a case, which is the failure the test exists to catch. + +**I7.** The printed output of `-E` is not the input with substitutions applied, and no property of it may be relied on beyond lexing to the same token sequence. +Established by: sections 3.8 and 2.1, and by `PREV_WHITE` being one bit. Checked by: nothing. May be broken by: nobody. Stated because build systems do rely on it, and a change to the spacing rules is not a bug in GCC. + +**I8.** Padding tokens are visible to the client of `cpp_get_token` and are not preprocessing tokens. +Established by: `cpp_get_token_1` returning them at three points in section 3.2. Checked by: nothing. May be broken by: nobody. A client that forgets them, as `funlike_invocation_p` must not, will read the token after a macro expansion as the token immediately after the macro name. + +**I9.** A directive is recognized only if the `#` is the first token on a logical line, and a `#` produced by a macro expansion never begins one. +Established by: the `BOL` flag test in `_cpp_lex_token` and the check in `_cpp_handle_directive` at `libcpp/directives.cc:454@releases/gcc-16.2.0`. Checked by: nothing. May be broken by: nobody. The comment at `libcpp/directives.cc:507@releases/gcc-16.2.0` calls the code that enforces the second half a kluge and gives `#define HASH #` as the case it exists for. + +*To be written: the invariants about buffer lifetime, and about what a client may hold across a call to `cpp_get_token`.* + +## 5. Observable behaviour + +Corpus entry `f02`, in `corpora/cpp/f02.json`, holds five macro tables, six expansions, thirty eight probed token pairs and four include traces, recorded on two configurations of GCC 16.2.0: a Homebrew build for `aarch64-apple-darwin24` and the Compiler Explorer build for `x86_64-linux-gnu`. The source spans it cites are in `corpora/source/f02.json`. + +### 5.1 The macro table before a line is read + +The program is one comment. The flag is `-dM -E`. + +| | aarch64-apple-darwin24 | x86_64-linux-gnu | +|---|---|---| +| macros defined | 443 | 408 | +| function-like | 15 | | +| defined to nothing | 3 | | +| names on both | 373 | 373 | +| names on one only | 70 | 35 | +| names on both, different values | 50 | 50 | + +Neither is a subset of the other, and 50 names are defined on both sides to different text, which is the set `#ifdef` cannot see. `__SIZEOF_LONG_DOUBLE__` is 8 against 16, `__INT_FAST16_TYPE__` is `short int` against `long int`, `__WINT_TYPE__` is `int` against `unsigned int`, and `__USER_LABEL_PREFIX__` is `_` against empty. + +What moves the count is not what a reader expects. + +| flags | effect on the table | +|---|---| +| `-O2` | adds `__OPTIMIZE__`, removes `__NO_INLINE__`, count unchanged | +| `-std=c23` | adds `__STRICT_ANSI__`, changes no value at all | +| `-ffast-math` | adds 7 names, changes 3, including `__GCC_IEC_559` from 2 to 0 | + +The `-std=c23` row is the one worth reading twice. The default for this compiler is `gnu23`, so the flag people reach for to select the language version selects a version that was already in force, and the only observable change is that the GNU extensions stop being advertised. + +### 5.2 What a dump of every macro leaves out + +19 of the 20 names in `builtin_array` do not appear in `-dM` output. `__STDC__` does, for the reason in section 2.6. `__FILE__` and `__LINE__` are absent from a dump that claims to print every macro, and are defined. + +### 5.3 A space that is in no input file + +```text +#define EMPTY +a+EMPTY+b +``` + +`gcc -E -P` prints `a+ +b`. Text substitution gives `a++b`. The difference is one space and nothing else, and it is there because the empty expansion left a padding token and `cpp_avoid_paste` was asked whether `+` may be printed against `+`. + +38 pairs of tokens were probed by putting them next to each other with nothing between them and preprocessing the result. 29 came back separated by a space. The 9 that did not are `+-`, `x+`, `*&`, `][`, `;;`, `&|`, `!!`, `~x` and `1]`, none of which lexes as a single token. The rule fires on the pairs that would change meaning and on no others. + +### 5.4 Expansion + +| program | output | +|---|---| +| `CAT(a, b)` with `#define CAT(x, y) x ## y` | `ab` | +| `CAT(PLUS, PLUS)` with `#define PLUS +` | `PLUSPLUS` | +| `STR(PLUS)` with `#define STR(x) #x` | `"PLUS"` | +| `XSTR(PLUS)` with `#define XSTR(x) STR(x)` | `"+"` | +| `foo` with `#define foo foo + 1` | `foo + 1` | +| `A` with `#define A B` and `#define B A` | `A` | +| `f(1)` with `#define f(x) [x]` | `[1]` | +| `f` with the same | `f` | +| `f (2)` with the same | `[2]` | + +Every one of these is the same on both targets, which is what makes them facts about the language rather than about a machine. + +### 5.5 Include guards + +Four headers, each included twice, differing by one line. + +| header | after the `#endif` | opens | +|---|---|---| +| `clean.h` | nothing | 1 | +| `untidy.h` | a comment | 1 | +| `stray.h` | one declaration | 2 | +| `bare.h` | no guard at all | 2 | + +The comment costs nothing because it produces no token. The declaration costs the optimization, and `stray.h` is read, lexed and skipped a second time for one `typedef`. + +`-H` prints no guard advice for any of these four, which looks like a broken experiment and is the specification. `report_missing_guard` at `libcpp/files.cc:2203@releases/gcc-16.2.0` reports a file only when `file->stack_count == 1`, at `libcpp/files.cc:2217@releases/gcc-16.2.0`, so the advice arrives for a file that has not yet cost anything and never for the one that has. The same four headers included once each do produce the report, naming `bare.h` and `stray.h`. + +### 5.6 Line markers + +Four lines of C, two of them `#include`, preprocessed with markers left in, which is the default. + +```text +# 0 "markers.c" +# 0 "" +# 0 "" +# 1 "markers.c" +# 1 "clean.h" 1 + + +int clean_thing; +# 2 "markers.c" 2 +int before; +# 1 "stray.h" 1 +``` + +Four markers before a byte of the program, naming three files, two of which are not files. The two blank lines after entering `clean.h` are the guard's `#ifndef` and `#define`, printed as newlines rather than as a marker because the gap is under 8 lines, which is the rule of section 3.8 in the output. The `1` after a filename is entering, the `2` is returning, and `# 4 "markers.c" 2` after `stray.h` is the return jumping over two lines that produced nothing. + +### 5.7 What one include costs + +Two lines of C, `#include ` and a `puts` call. + +| | aarch64-apple-darwin24 | x86_64-linux-gnu | +|---|---|---| +| files opened | 42 | 31 | +| distinct files | 38 | 25 | +| deepest nesting | 6 | 6 | +| files in common | 0 | 0 | + +Not one path appears on both sides. The header is the same header in the standard's sense and shares no file with itself across two machines. + +*To be written: `-dD`, `-dU` and `-dI` as observable output, and what `-fdirectives-only` changes.* + +## 6. Edge cases and error paths + +- **A function-like macro name with no following bracket.** Not an invocation. The name is printed as itself. The lookahead in `funlike_invocation_p` backs up whatever it read, including through a newline, so a macro name at the end of one line and a bracket at the start of the next is an invocation. +- **A paste that does not lex.** `paste_tokens` reports `pasting X and Y does not give a valid preprocessing token` at `libcpp/macro.cc:1076@releases/gcc-16.2.0`, clears `PASTE_LEFT`, and emits both operands separately. This is an error for every language except `CLK_ASM`. +- **A paste that lexes as the wrong thing.** No diagnostic, because from the lexer's point of view nothing went wrong. Section 5.4's `PLUSPLUS` is this case. +- **Wrong argument count.** `macro %qs requires %u arguments, but only %u given` at `libcpp/macro.cc:1219@releases/gcc-16.2.0`, or `macro %qs passed %u arguments, but takes just %u` at `libcpp/macro.cc:1224@releases/gcc-16.2.0`, each followed by a note pointing at the definition. +- **An unterminated argument list.** `unterminated argument list invoking macro %qs` at `libcpp/macro.cc:1423@releases/gcc-16.2.0`, raised when the collector reaches the end of the file with brackets open. +- **`#` not followed by a parameter, in a function-like macro.** `libcpp/macro.cc:3812@releases/gcc-16.2.0`. In an object-like macro `#` is an ordinary token. +- **`##` at either end of a replacement list.** `libcpp/macro.cc:3696@releases/gcc-16.2.0`, and a separate message for `__VA_OPT__` at `libcpp/macro.cc:94@releases/gcc-16.2.0`. +- **Include recursion.** The depth limit is 200, set in `cpp_create_reader` at `libcpp/init.cc:235@releases/gcc-16.2.0` and enforced at `libcpp/directives.cc:947@releases/gcc-16.2.0`. The message names `-fmax-include-depth`. +- **A header reached by two different paths.** With `#pragma once`, recognized by comparing contents, at the cost described in section 3.7. With an include guard, recognized because the guard macro is defined, at no cost. Without either, read twice. +- **A guard macro that is undefined between inclusions.** The file is read again. This is supported and is how a header meant to be included several times with different macros set is written. +- **A guard whose `#ifndef` and `#define` name different macros.** `do_define` records the mismatch at `libcpp/directives.cc:715@releases/gcc-16.2.0` and `_cpp_pop_file_buffer` warns at `libcpp/files.cc:2337@releases/gcc-16.2.0`, `header guard X followed by #define of a different macro`, but only under `-Wheader-guard` and only when the front end's spelling corrector says the two names are close enough to be a typo. Without the warning the header still works and is read every time, which is the failure this exists to catch. +- **An `#if` whose expression cannot be evaluated.** Out of scope for this document, and in `libcpp/expr.cc`. The one thing it contributes here is that a `#if defined(X)` at the top of a file can be a controlling macro, recorded through `mi_ind_cmacro` at `libcpp/expr.cc:1243@releases/gcc-16.2.0`. + +*To be written: what happens when a file disappears between the `stat` and the `open`, and the behaviour of a directive inside a macro argument list.* + +## 7. Interactions + +libcpp is called by every C family front end and by nothing else in GCC. The client supplies a `cpp_callbacks` at `libcpp/include/cpplib.h:783@releases/gcc-16.2.0`, which is how the preprocessor tells the front end about a `#define`, an `#include`, a line change or a pragma without knowing what a front end is. The `-E` printer is a client that implements those callbacks by printing, at `gcc/c-family/c-ppoutput.cc:704@releases/gcc-16.2.0` and after. + +The line map is shared. libcpp owns `line_table` and every `location_t` in the compiler, including ones attached to GIMPLE statements thousands of passes later, is a key into the same structure this document's tokens use. `trace_include` at `libcpp/line-map.cc:1592@releases/gcc-16.2.0`, which is what `-H` prints, lives there rather than in `files.cc` for that reason. + +The macro table is written by three parties: libcpp for the built-ins of section 2.6, `gcc/c-family/c-cppbuiltin.cc` for the language and machine macros, and the target through `TARGET_CPU_CPP_BUILTINS`. Section 5.1's count is the sum, and only the first of the three is in this document. + +Options reach libcpp as a `cpp_options` at `libcpp/include/cpplib.h:359@releases/gcc-16.2.0`, filled in by the front end from the command line. The ones that change the algorithms here rather than the diagnostics are `lang`, which selects the standard and therefore the token types that exist, `traditional`, which selects a different preprocessor entirely, and `max_include_depth`. + +*To be written: the PCH interaction, and what `-fdirectives-only` does to the lexer.* + +## 8. Conformance + +GCC's own tests for the preprocessor are in `gcc/testsuite/gcc.dg/cpp`, which is several hundred files, and in `libcpp`'s share of `gcc/testsuite/gcc.dg/`. The subsets that bear on this document are the `macro` family for sections 3.3 to 3.6, `mi*.c` for the multiple include optimization of section 3.7, and `avoidpaste1.c` and `avoidpaste2.c` for the spacing rule of section 3.8, which are the only tests anywhere that assert what `-E` output looks like rather than what it means. + +This project's own check is `tests/test_cpp.py`, which is not a conformance suite for GCC. It checks that the reader in `gxray.cpp` agrees with the source: that its table of paste-avoiding pairs covers exactly the 22 case labels of `cpp_avoid_paste` in the pinned tree, minus the six about pragmas and user-defined literal suffixes that a `-E` of a C file cannot produce, plus the range test before the switch, which is a reason without a label, that the range test is still written the way the reader assumes, that the advice condition of section 5.5 is still `file->stack_count == 1`, and that every line marker flag the reader names is one `gcc/doc/cpp.texi` documents. + +*To be written: the invariants of section 4 restated as assertions, and which of them the recorded corpus can check.* + +## 9. Port notes + +The preprocessor's algorithms are target independent and its output is not. Nothing in sections 3.1 to 3.8 asks the target anything. Everything in section 5.1 is the target answering. + +| | aarch64-apple-darwin24 | x86_64-linux-gnu | +|---|---|---| +| macros before the first line | 443 | 408 | +| files opened by one `#include ` | 42 | 31 | +| distinct files | 38 | 25 | +| files in common with the other column | 0 | 0 | +| expansion results that differ | 0 of 6 | 0 of 6 | + +The last row is the one that says where the boundary is. Two compilers that share no header file and disagree about 50 macro values agree exactly on what `#define foo foo + 1` does, because that is the language and the rest is the machine. + +**What is forced and what is not.** The token stream interface is forced by the standard, which defines translation in terms of preprocessing tokens rather than text, and any implementation that works in text will get section 5.3 wrong. The one bit of whitespace in `PREV_WHITE` is not forced: an implementation that wanted `-E` output to round trip could keep a column and reproduce the original spacing, at the cost of a wider token. GCC's choice makes the token small and makes the output a rendering, and I7 is the consequence. + +Interning every identifier is not forced either, but `NODE_DISABLED` depends on it. An implementation that compared macro names by string would need the disabled set to live somewhere else, and the obvious somewhere else is a set on the expansion stack, which turns section 3.6 from two flag assignments into a search. + +The multiple include optimization is entirely optional and entirely worth it. An implementation may read a guarded header a hundred times and get the same answer, slowly. What is not optional, if the optimization is implemented, is the exactness of the condition: a file with one token after its `#endif` must be read again, and section 5.5 is what that looks like when it works. + +The 8 in section 3.8's line marker rule and the 200 include depth are both arbitrary. Nothing else in this document is a number a reimplementation gets to choose. diff --git a/citations.lock.json b/citations.lock.json index 0f3f52a..70e0f84 100644 --- a/citations.lock.json +++ b/citations.lock.json @@ -227,6 +227,58 @@ "hash": "4de52375ef4441f9", "text": "c_common_parse_file (void)" }, + "gcc/c-family/c-ppoutput.cc:218@releases/gcc-16.2.0": { + "hash": "e9bcffdff0d519cd", + "text": "token_streamer::stream (cpp_reader *pfile, const cpp_token *token," + }, + "gcc/c-family/c-ppoutput.cc:244@releases/gcc-16.2.0": { + "hash": "8b3f49b93f333835", + "text": " /* Subtle logic to output a space if and only if necessary. */" + }, + "gcc/c-family/c-ppoutput.cc:400@releases/gcc-16.2.0": { + "hash": "23a76fdcf71d63bd", + "text": "scan_translation_unit (cpp_reader *pfile)" + }, + "gcc/c-family/c-ppoutput.cc:541@releases/gcc-16.2.0": { + "hash": "8c0c5521dbf7ffb0", + "text": "maybe_print_line_1 (location_t src_loc, FILE *stream)" + }, + "gcc/c-family/c-ppoutput.cc:555@releases/gcc-16.2.0": { + "hash": "4b56dfc58934998a", + "text": " if (!flag_no_line_commands" + }, + "gcc/c-family/c-ppoutput.cc:557@releases/gcc-16.2.0": { + "hash": "deab684cebb7ce7d", + "text": " && src_line < print.src_line + 8" + }, + "gcc/c-family/c-ppoutput.cc:592@releases/gcc-16.2.0": { + "hash": "6b59beae7a61c20d", + "text": "print_line_1 (location_t src_loc, const char *special_flags, FILE *stream)" + }, + "gcc/c-family/c-ppoutput.cc:601@releases/gcc-16.2.0": { + "hash": "967915ff887e3243", + "text": " if (src_loc != UNKNOWN_LOCATION && !flag_no_line_commands)" + }, + "gcc/c-family/c-ppoutput.cc:618@releases/gcc-16.2.0": { + "hash": "905cf0c8f5965f5b", + "text": " fprintf (stream, \"# %u \\\"%s\\\"%s\"," + }, + "gcc/c-family/c-ppoutput.cc:621@releases/gcc-16.2.0": { + "hash": "32b1e8507b805315", + "text": " int sysp = in_system_header_at (src_loc);" + }, + "gcc/c-family/c-ppoutput.cc:704@releases/gcc-16.2.0": { + "hash": "abbe9c2491ce67ce", + "text": "cb_define (cpp_reader *pfile, location_t line, cpp_hashnode *node)" + }, + "gcc/c-family/c-ppoutput.cc:89@releases/gcc-16.2.0": { + "hash": "3b4dfb51e8c5c3ee", + "text": "preprocess_file (cpp_reader *pfile)" + }, + "gcc/c-family/c-ppoutput.cc:903@releases/gcc-16.2.0": { + "hash": "d544ab13c02a08b3", + "text": "/* Dump out the hash table. */" + }, "gcc/c-family/c-pragma.cc:1885@releases/gcc-16.2.0": { "hash": "c3e35ae22c26daf3", "text": " invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL);" @@ -487,6 +539,10 @@ "hash": "07597b53c560bf31", "text": " echo \"source ${srcdir}/gdbasan.in\" >> .gdbinit" }, + "gcc/cp/parser.cc:1677@releases/gcc-16.2.0": { + "hash": "00865c4dcbf0395e", + "text": " TTYPE_TABLE" + }, "gcc/dbgcnt.cc:111@releases/gcc-16.2.0": { "hash": "921715c7fd606a3c", "text": "static int" @@ -511,6 +567,10 @@ "hash": "8ce555db7f83b3ff", "text": "bool" }, + "gcc/doc/cpp.texi:4072@releases/gcc-16.2.0": { + "hash": "8809ba12a075b4cd", + "text": "After the file name comes zero or more flags, which are @samp{1}," + }, "gcc/doc/install.texi:570@releases/gcc-16.2.0": { "hash": "3a40495cb53da586", "text": "@item DejaGnu version 1.5.3 (or later)" @@ -2030,6 +2090,362 @@ "gcc/wide-int.h:23@releases/gcc-16.2.0": { "hash": "511812f39f5d18c9", "text": "/* wide-int.[cc|h] implements a class that efficiently performs" + }, + "libcpp/directives.cc:151@releases/gcc-16.2.0": { + "hash": "cdda0412df1be7d7", + "text": "#define DIRECTIVE_TABLE\t\t\t\t\t\t\t\\" + }, + "libcpp/directives.cc:2670@releases/gcc-16.2.0": { + "hash": "1386bb6198b1f929", + "text": " ifs->mi_cmacro = 0;" + }, + "libcpp/directives.cc:2771@releases/gcc-16.2.0": { + "hash": "1bf2bde0512eab18", + "text": " ifs->mi_cmacro = 0;" + }, + "libcpp/directives.cc:2807@releases/gcc-16.2.0": { + "hash": "87e83acefe5aaabf", + "text": "\t pfile->mi_valid = true;" + }, + "libcpp/directives.cc:2843@releases/gcc-16.2.0": { + "hash": "103d7f4f263c6be9", + "text": " if (pfile->mi_valid && pfile->mi_cmacro == 0)" + }, + "libcpp/directives.cc:454@releases/gcc-16.2.0": { + "hash": "2f40fc0e15831fb2", + "text": "_cpp_handle_directive (cpp_reader *pfile, bool indented)" + }, + "libcpp/directives.cc:504@releases/gcc-16.2.0": { + "hash": "51e807bffd21a93e", + "text": " if (! (dir->flags & IF_COND))" + }, + "libcpp/directives.cc:507@releases/gcc-16.2.0": { + "hash": "9795c3dc0729f828", + "text": " /* Kluge alert. In order to be sure that code like this" + }, + "libcpp/directives.cc:700@releases/gcc-16.2.0": { + "hash": "fca78489ac9eb9de", + "text": " if (pfile->mi_valid" + }, + "libcpp/directives.cc:715@releases/gcc-16.2.0": { + "hash": "8331da024d9de2a0", + "text": "\t ifs->mi_def_cmacro = node;" + }, + "libcpp/directives.cc:720@releases/gcc-16.2.0": { + "hash": "46804e420bf8752b", + "text": " pfile->mi_valid = false;" + }, + "libcpp/directives.cc:947@releases/gcc-16.2.0": { + "hash": "3a52d6c9e15283a5", + "text": " if (pfile->line_table->depth >= CPP_OPTION (pfile, max_include_depth))" + }, + "libcpp/expr.cc:1243@releases/gcc-16.2.0": { + "hash": "0b64682751de623f", + "text": " pfile->mi_ind_cmacro = node;" + }, + "libcpp/files.cc:2203@releases/gcc-16.2.0": { + "hash": "61aeed2b11ba295e", + "text": "report_missing_guard (void **slot, void *d)" + }, + "libcpp/files.cc:2214@releases/gcc-16.2.0": { + "hash": "36c8fda1d3da7639", + "text": " /* We don't want MI guard advice for the main file. */" + }, + "libcpp/files.cc:2217@releases/gcc-16.2.0": { + "hash": "f51caa197577f5d7", + "text": "\t && file->stack_count == 1" + }, + "libcpp/files.cc:2326@releases/gcc-16.2.0": { + "hash": "0ff1962cf5415800", + "text": " if (pfile->mi_valid && file->cmacro == NULL)" + }, + "libcpp/files.cc:2337@releases/gcc-16.2.0": { + "hash": "62ac37d41d037a91", + "text": "\t && cpp_warning_with_line (pfile, CPP_W_HEADER_GUARD," + }, + "libcpp/files.cc:54@releases/gcc-16.2.0": { + "hash": "10cc4ce103ce0c72", + "text": "struct _cpp_file" + }, + "libcpp/files.cc:80@releases/gcc-16.2.0": { + "hash": "3531c24f6167cf3c", + "text": " const cpp_hashnode *cmacro;" + }, + "libcpp/files.cc:840@releases/gcc-16.2.0": { + "hash": "31e98082beda5d73", + "text": "is_known_idempotent_file (cpp_reader *pfile, _cpp_file *file, bool import)" + }, + "libcpp/files.cc:858@releases/gcc-16.2.0": { + "hash": "78b2ced29fa0dacb", + "text": " /* Skip if the file had a header guard and the macro is defined." + }, + "libcpp/files.cc:880@releases/gcc-16.2.0": { + "hash": "7e7f3a4aa9aebcce", + "text": "has_unique_contents (cpp_reader *pfile, _cpp_file *file, bool import," + }, + "libcpp/include/cpplib.h:1004@releases/gcc-16.2.0": { + "hash": "05bd72cb27ca683b", + "text": "#define NODE_OPERATOR\t(1 << 0)\t/* C++ named operator. */" + }, + "libcpp/include/cpplib.h:1008@releases/gcc-16.2.0": { + "hash": "ac9e1848cf513bdd", + "text": "#define NODE_DISABLED\t(1 << 4)\t/* A disabled macro. */" + }, + "libcpp/include/cpplib.h:1015@releases/gcc-16.2.0": { + "hash": "1e32ca766d9fcc29", + "text": "enum node_type" + }, + "libcpp/include/cpplib.h:1026@releases/gcc-16.2.0": { + "hash": "6bcaa72dbbb9ff0b", + "text": "enum cpp_builtin_type" + }, + "libcpp/include/cpplib.h:1069@releases/gcc-16.2.0": { + "hash": "bb780c152b57af0f", + "text": "struct GTY(()) cpp_hashnode {" + }, + "libcpp/include/cpplib.h:152@releases/gcc-16.2.0": { + "hash": "94fc6f7a4300fbc8", + "text": " TK(COMMENT,\t\tLITERAL) /* Only if output comments. */\t\\" + }, + "libcpp/include/cpplib.h:157@releases/gcc-16.2.0": { + "hash": "60de07dc0e38f404", + "text": " TK(PADDING,\t\tNONE)\t /* Whitespace for -E.\t*/" + }, + "libcpp/include/cpplib.h:161@releases/gcc-16.2.0": { + "hash": "65bbb1f718c2b2cb", + "text": "enum cpp_ttype" + }, + "libcpp/include/cpplib.h:199@releases/gcc-16.2.0": { + "hash": "7856ece3f85e306d", + "text": "#define PREV_WHITE\t(1 << 0) /* If whitespace before this token. */" + }, + "libcpp/include/cpplib.h:261@releases/gcc-16.2.0": { + "hash": "34e4ebd0700ebc9c", + "text": "/* A preprocessing token. This occupies 32 bytes on a 64-bit host. On a" + }, + "libcpp/include/cpplib.h:265@releases/gcc-16.2.0": { + "hash": "50b7b84fd2696a2b", + "text": "struct GTY(()) cpp_token {" + }, + "libcpp/include/cpplib.h:297@releases/gcc-16.2.0": { + "hash": "4ef35841ed9326ff", + "text": "extern enum cpp_token_fld_kind cpp_token_val_index (const cpp_token *tok);" + }, + "libcpp/include/cpplib.h:359@releases/gcc-16.2.0": { + "hash": "845bd9578dbd2c76", + "text": "struct cpp_options" + }, + "libcpp/include/cpplib.h:43@releases/gcc-16.2.0": { + "hash": "57b9c8b5da9e0761", + "text": "/* The first three groups, apart from '=', can appear in preprocessor" + }, + "libcpp/include/cpplib.h:54@releases/gcc-16.2.0": { + "hash": "fa85a0e3a2e30ad8", + "text": "#define TTYPE_TABLE\t\t\t\t\t\t\t\\" + }, + "libcpp/include/cpplib.h:783@releases/gcc-16.2.0": { + "hash": "60bebbdfb3e23b8b", + "text": "struct cpp_callbacks" + }, + "libcpp/include/cpplib.h:930@releases/gcc-16.2.0": { + "hash": "fd113b9d7b63acea", + "text": "struct GTY(()) cpp_macro {" + }, + "libcpp/init.cc:235@releases/gcc-16.2.0": { + "hash": "0ce93728bb8bc698", + "text": " CPP_OPTION (pfile, max_include_depth) = 200;" + }, + "libcpp/init.cc:448@releases/gcc-16.2.0": { + "hash": "30e45a3fa3045d90", + "text": "#define B(n, t, f) { DSC(n), t, f }" + }, + "libcpp/init.cc:449@releases/gcc-16.2.0": { + "hash": "5811e6b1b965c618", + "text": "static const struct builtin_macro builtin_array[] =" + }, + "libcpp/init.cc:539@releases/gcc-16.2.0": { + "hash": "f9a9e13f50f0a67f", + "text": "cpp_init_special_builtins (cpp_reader *pfile)" + }, + "libcpp/init.cc:589@releases/gcc-16.2.0": { + "hash": "338b01bda44d67fa", + "text": "cpp_init_builtins (cpp_reader *pfile, int hosted)" + }, + "libcpp/init.cc:596@releases/gcc-16.2.0": { + "hash": "b856805a75b28f4a", + "text": " _cpp_define_builtin (pfile, \"__STDC__ 1\");" + }, + "libcpp/init.cc:606@releases/gcc-16.2.0": { + "hash": "d7579a2b276e8fa9", + "text": "\t_cpp_define_builtin (pfile, \"__cplusplus 202400L\");" + }, + "libcpp/init.cc:639@releases/gcc-16.2.0": { + "hash": "fef1bf3f0cabbf4a", + "text": " _cpp_define_builtin (pfile, \"__STDC_VERSION__ 202311L\");" + }, + "libcpp/lex.cc:1082@releases/gcc-16.2.0": { + "hash": "ca91ed2fb10b274d", + "text": "_cpp_process_line_notes (cpp_reader *pfile, int in_comment)" + }, + "libcpp/lex.cc:27@releases/gcc-16.2.0": { + "hash": "745d6078803da697", + "text": "enum spell_type" + }, + "libcpp/lex.cc:3460@releases/gcc-16.2.0": { + "hash": "1f953eb0eb598c96", + "text": "_cpp_temp_token (cpp_reader *pfile)" + }, + "libcpp/lex.cc:3725@releases/gcc-16.2.0": { + "hash": "f62a042e34f0cf4c", + "text": "_cpp_lex_token (cpp_reader *pfile)" + }, + "libcpp/lex.cc:3796@releases/gcc-16.2.0": { + "hash": "0dd00b3ea813f688", + "text": " pfile->mi_valid = false;" + }, + "libcpp/lex.cc:3888@releases/gcc-16.2.0": { + "hash": "354847ebd1fed06d", + "text": "_cpp_lex_direct (cpp_reader *pfile)" + }, + "libcpp/lex.cc:4637@releases/gcc-16.2.0": { + "hash": "7d2e8d22ce907006", + "text": "cpp_output_token (const cpp_token *token, FILE *fp)" + }, + "libcpp/lex.cc:46@releases/gcc-16.2.0": { + "hash": "3fdb2495f40bec30", + "text": "static const struct token_spelling token_spellings[N_TTYPES] = { TTYPE_TABLE };" + }, + "libcpp/lex.cc:4723@releases/gcc-16.2.0": { + "hash": "dfadb85438951fc1", + "text": "/* Returns nonzero if a space should be inserted to avoid an" + }, + "libcpp/lex.cc:4728@releases/gcc-16.2.0": { + "hash": "c14373dc0502dc25", + "text": "cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1," + }, + "libcpp/lex.cc:877@releases/gcc-16.2.0": { + "hash": "4b0433c06643d156", + "text": "_cpp_clean_line (cpp_reader *pfile)" + }, + "libcpp/line-map.cc:1589@releases/gcc-16.2.0": { + "hash": "152aaaa8e178e8ac", + "text": "/* Print an include trace, for e.g. the -H option of the preprocessor. */" + }, + "libcpp/line-map.cc:1592@releases/gcc-16.2.0": { + "hash": "ea270a1e478c11dd", + "text": "trace_include (const class line_maps *set, const line_map_ordinary *map)" + }, + "libcpp/line-map.cc:570@releases/gcc-16.2.0": { + "hash": "a882749186e5f1a7", + "text": "linemap_add (line_maps *set, enum lc_reason reason," + }, + "libcpp/macro.cc:1029@releases/gcc-16.2.0": { + "hash": "df841b32afdd7ce7", + "text": "paste_tokens (cpp_reader *pfile, location_t location," + }, + "libcpp/macro.cc:1076@releases/gcc-16.2.0": { + "hash": "ded61157d6a2d157", + "text": "\tcpp_error_with_line (pfile, CPP_DL_ERROR, location, 0," + }, + "libcpp/macro.cc:1098@releases/gcc-16.2.0": { + "hash": "7d90ac287cfa557c", + "text": "paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)" + }, + "libcpp/macro.cc:1219@releases/gcc-16.2.0": { + "hash": "d057c4d8ce26b259", + "text": " cpp_error (pfile, CPP_DL_ERROR," + }, + "libcpp/macro.cc:1224@releases/gcc-16.2.0": { + "hash": "f69e5574cae61975", + "text": " cpp_error (pfile, CPP_DL_ERROR," + }, + "libcpp/macro.cc:1249@releases/gcc-16.2.0": { + "hash": "9f8e4471e24cf502", + "text": "collect_args (cpp_reader *pfile, const cpp_hashnode *node," + }, + "libcpp/macro.cc:1423@releases/gcc-16.2.0": { + "hash": "98db09a468b45ad0", + "text": "\t\t \"unterminated argument list invoking macro %qs\"," + }, + "libcpp/macro.cc:1431@releases/gcc-16.2.0": { + "hash": "3c59dde6bfc51660", + "text": " if (_cpp_arguments_ok (pfile, macro, node, argc))" + }, + "libcpp/macro.cc:1463@releases/gcc-16.2.0": { + "hash": "9b93669187d3a8be", + "text": "funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node," + }, + "libcpp/macro.cc:1527@releases/gcc-16.2.0": { + "hash": "9b18a98e6d7cfe5b", + "text": "enter_macro_context (cpp_reader *pfile, cpp_hashnode *node," + }, + "libcpp/macro.cc:1589@releases/gcc-16.2.0": { + "hash": "22cc37aeea9a5c7c", + "text": " /* Disable the macro within its expansion. */" + }, + "libcpp/macro.cc:1590@releases/gcc-16.2.0": { + "hash": "5cc921e3766f70d5", + "text": " node->flags |= NODE_DISABLED;" + }, + "libcpp/macro.cc:1987@releases/gcc-16.2.0": { + "hash": "53db1201e92e4b24", + "text": "replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro," + }, + "libcpp/macro.cc:2454@releases/gcc-16.2.0": { + "hash": "19e5729e224b65c3", + "text": "padding_token (cpp_reader *pfile, const cpp_token *source)" + }, + "libcpp/macro.cc:2768@releases/gcc-16.2.0": { + "hash": "57dba03a4f8d3381", + "text": "expand_arg (cpp_reader *pfile, macro_arg *arg)" + }, + "libcpp/macro.cc:2856@releases/gcc-16.2.0": { + "hash": "0a935be90b31f8f7", + "text": "_cpp_pop_context (cpp_reader *pfile)" + }, + "libcpp/macro.cc:3006@releases/gcc-16.2.0": { + "hash": "78efa0bed9a5c54f", + "text": "cpp_get_token_1 (cpp_reader *pfile, location_t *location)" + }, + "libcpp/macro.cc:3066@releases/gcc-16.2.0": { + "hash": "c4de7895a1ecc060", + "text": "\t && !cpp_get_deferred_macro (pfile, node, result->src_loc))" + }, + "libcpp/macro.cc:3097@releases/gcc-16.2.0": { + "hash": "76cb03ad6f2a5c16", + "text": "\t\t node = pfile->cb.macro_to_expand (pfile, result);" + }, + "libcpp/macro.cc:3129@releases/gcc-16.2.0": { + "hash": "1b173ac75479f51a", + "text": "\t cpp_token *t = _cpp_temp_token (pfile);" + }, + "libcpp/macro.cc:3131@releases/gcc-16.2.0": { + "hash": "e06939185536e029", + "text": "\t t->flags = result->flags | NO_EXPAND;" + }, + "libcpp/macro.cc:3265@releases/gcc-16.2.0": { + "hash": "deef02b3bde0c60f", + "text": "cpp_get_token (cpp_reader *pfile)" + }, + "libcpp/macro.cc:3379@releases/gcc-16.2.0": { + "hash": "673cd418aaf4f94d", + "text": "_cpp_backup_tokens (cpp_reader *pfile, unsigned int count)" + }, + "libcpp/macro.cc:3696@releases/gcc-16.2.0": { + "hash": "74a46b0224cfb765", + "text": " N_(\"%<##%> cannot appear at either end of a macro expansion\");" + }, + "libcpp/macro.cc:3812@releases/gcc-16.2.0": { + "hash": "8eedb842025232cc", + "text": "\t\t\t \"%<#%> is not followed by a macro parameter\");" + }, + "libcpp/macro.cc:931@releases/gcc-16.2.0": { + "hash": "73b0c9f1b8b9d88e", + "text": "stringify_arg (cpp_reader *pfile, const cpp_token **first, unsigned int count)" + }, + "libcpp/macro.cc:94@releases/gcc-16.2.0": { + "hash": "69de4ccdd00e75b9", + "text": " N_(\"'##' cannot appear at either end of __VA_OPT__\");" } } } diff --git a/corpora/cpp/f02.json b/corpora/cpp/f02.json new file mode 100644 index 0000000..47861c2 --- /dev/null +++ b/corpora/cpp/f02.json @@ -0,0 +1,420 @@ +{ + "recorded": "2026-09-06", + "tag": "releases/gcc-16.2.0", + "compiler": "gcc-16 (Homebrew GCC 16.2.0) 16.2.0", + "target": "aarch64-apple-darwin24", + "cache": [ + "32e12e027eab29cf8c9c8bdded42e8ab", + "6e056683d5f98988c2723fa1411181ea", + "8c6c8a242b28ac906e721b4315f002c7", + "b052b8da4cb7550d4d587e32552932fe", + "b8aad3f4e7ae4a0cd93b6026890dd086", + "bb11d647f8eaf8ed57950802ec869710", + "ef9027019a0b32786c5c64e0e0652d71", + "feded2677aff4cb36cb66975aa68b30e" + ], + "headers_source": { + "clean.h": "#ifndef CLEAN_H\n#define CLEAN_H\nint clean_thing;\n#endif\n", + "untidy.h": "#ifndef UNTIDY_H\n#define UNTIDY_H\nint untidy_thing;\n#endif\n/* a comment, outside the guard */\n", + "stray.h": "#ifndef STRAY_H\n#define STRAY_H\nint stray_thing;\n#endif\ntypedef int stray_t;\n", + "bare.h": "int bare_thing;\n" + }, + "macros": { + "local": { + "text": "#define __builtin_nanq __builtin_nanf128\n#define __DBL_MIN_EXP__ (-1021)\n#define __UINT_LEAST16_MAX__ 0xffff\n#define __ARM_SIZEOF_WCHAR_T 4\n#define __ATOMIC_ACQUIRE 2\n#define __FLT128_MAX_10_EXP__ 4932\n#define __ARM_STATE_ZT0 1\n#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n#define __GCC_IEC_559_COMPLEX 2\n#define __UINT_LEAST8_TYPE__ unsigned char\n#define __INTMAX_C(c) c ## L\n#define __CHAR_BIT__ 8\n#define __UINT8_MAX__ 0xff\n#define __USER_LABEL_PREFIX__ _\n#define __WINT_MAX__ 0x7fffffff\n#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_MIN_10_EXP__ (-37)\n#define __arm_streaming_compatible [[__extension__ arm::streaming_compatible]]\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1\n#define __GCC_ATOMIC_CHAR_LOCK_FREE 2\n#define __ARM_FEATURE_ATOMICS 1\n#define __GCC_IEC_559 2\n#define __FLT32X_DECIMAL_DIG__ 17\n#define __builtin_nansq __builtin_nansf128\n#define __FLT_EVAL_METHOD__ 0\n#define __FLT64_DECIMAL_DIG__ 17\n#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2\n#define __INTPTR_WIDTH__ 64\n#define __UINT_FAST32_TYPE__ unsigned int\n#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL\n#define __SIG_ATOMIC_TYPE__ int\n#define __ARM_FEATURE_RCPC 1\n#define __DBL_MIN_10_EXP__ (-307)\n#define __FINITE_MATH_ONLY__ 0\n#define __PTRDIFF_MAX__ 0x7fffffffffffffffL\n#define __FLT32X_MAX_EXP__ 1024\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1\n#define __GNUC_PATCHLEVEL__ 0\n#define __FLT32_HAS_DENORM__ 1\n#define __UINT_FAST8_MAX__ 0xff\n#define __FLT32_MAX_10_EXP__ 38\n#define __DEC64_MAX_EXP__ 385\n#define __INT8_C(c) c\n#define __ARM_64BIT_STATE 1\n#define __INT_LEAST8_WIDTH__ 8\n#define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL\n#define __SHRT_MAX__ 0x7fff\n#define __ARM_FEATURE_IDIV 1\n#define __FLT64X_MAX_10_EXP__ 4932\n#define __BFLT16_MAX_EXP__ 128\n#define __ARM_NEON_SVE_BRIDGE 1\n#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __LDBL_IS_IEC_60559__ 1\n#define __ARM_FP 14\n#define __FLT64X_IS_IEC_60559__ 1\n#define __FLT64X_HAS_QUIET_NAN__ 1\n#define __UINT_LEAST8_MAX__ 0xff\n#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128\n#define __APPLE_CC__ 1\n#define __UINTMAX_TYPE__ long unsigned int\n#define __BFLT16_DECIMAL_DIG__ 4\n#define __DEC32_EPSILON__ 1E-6DF\n#define __FLT_EVAL_METHOD_TS_18661_3__ 0\n#define __UINT32_MAX__ 0xffffffffU\n#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)\n#define __AARCH64_CMODEL_SMALL__ 1\n#define __LDBL_MAX_EXP__ 1024\n#define __STDC_EMBED_NOT_FOUND__ 0\n#define __INT_FAST32_WIDTH__ 32\n#define __FLT128_MIN_EXP__ (-16381)\n#define __DEC64X_MAX_EXP__ 6145\n#define __FLT128_MIN_10_EXP__ (-4931)\n#define __FLT32X_IS_IEC_60559__ 1\n#define __INT_LEAST16_WIDTH__ 16\n#define __SCHAR_MAX__ 0x7f\n#define __FLT128_MANT_DIG__ 113\n#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)\n#define __INT64_C(c) c ## LL\n#define __GCC_ATOMIC_POINTER_LOCK_FREE 2\n#define __ATOMIC_SEQ_CST 5\n#define __SIZEOF_INT__ 4\n#define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL\n#define __ARM_FEATURE_CLZ 1\n#define __ARM_STATE_ZA 1\n#define __FLT32X_MANT_DIG__ 53\n#define __LDBL_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT64X_EPSILON__ 1.92592994438723585305597794258492732e-34F64x\n#define __STDC_HOSTED__ 1\n#define __DEC64_MIN_EXP__ (-382)\n#define __DBL_DIG__ 15\n#define __STDC_EMBED_EMPTY__ 2\n#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n#define __SHRT_WIDTH__ 16\n#define __DEC64_MIN__ 1E-383DD\n#define __FLT32_IS_IEC_60559__ 1\n#define __LDBL_MIN__ 2.22507385850720138309023271733240406e-308L\n#define __STDC_UTF_16__ 1\n#define __DBL_IS_IEC_60559__ 1\n#define __DEC32_MAX__ 9.999999E96DF\n#define __FLT16_HAS_QUIET_NAN__ 1\n#define __CHAR8_TYPE__ unsigned char\n#define __strong \n#define __ARM_SIZEOF_MINIMAL_ENUM 4\n#define __FLT64X_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F64x\n#define __FP_FAST_FMA 1\n#define __FLT32X_HAS_INFINITY__ 1\n#define __FLT16_DIG__ 3\n#define __INT_WIDTH__ 32\n#define __BFLT16_DIG__ 2\n#define __SIZE_WIDTH__ 64\n#define __ARM_FEATURE_JCVT 1\n#define __APPLE__ 1\n#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2\n#define __DECIMAL_DIG__ 17\n#define __ARM_FEATURE_DOTPROD 1\n#define __INT16_MAX__ 0x7fff\n#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL\n#define __FLT64X_MIN_10_EXP__ (-4931)\n#define __LDBL_HAS_QUIET_NAN__ 1\n#define __FLT16_MIN_EXP__ (-13)\n#define __FLT64_MANT_DIG__ 53\n#define __LDBL_MANT_DIG__ 53\n#define __FLT64X_MANT_DIG__ 113\n#define __DYNAMIC__ 1\n#define __GNUC__ 16\n#define __FLT16_DECIMAL_DIG__ 5\n#define __FLT_HAS_DENORM__ 1\n#define __SIZEOF_LONG_DOUBLE__ 8\n#define __arm_new(...) [[__extension__ arm::new(__VA_ARGS__)]]\n#define __LDBL_DIG__ 15\n#define __SIZE_TYPE__ long unsigned int\n#define __FLT64_MAX_10_EXP__ 308\n#define __INTMAX_TYPE__ long int\n#define __FLT16_MAX_10_EXP__ 4\n#define __INT_FAST32_MAX__ 0x7fffffff\n#define __DBL_HAS_INFINITY__ 1\n#define __HAVE_SPECULATION_SAFE_VALUE 1\n#define __DEC32_MIN_EXP__ (-94)\n#define __builtin_huge_valq __builtin_huge_valf128\n#define __FLT32X_HAS_DENORM__ 1\n#define __INT_FAST16_TYPE__ short int\n#define __LDBL_HAS_DENORM__ 1\n#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16\n#define __FLT128_HAS_INFINITY__ 1\n#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL\n#define __DEC32_MIN__ 1E-95DF\n#define __weak \n#define __ARM_FEATURE_FRINT 1\n#define __DBL_MAX_EXP__ 1024\n#define __WCHAR_WIDTH__ 32\n#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __DEC128_EPSILON__ 1E-33DL\n#define __GCC_ATOMIC_LONG_LOCK_FREE 2\n#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16\n#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x\n#define __FLT32_HAS_QUIET_NAN__ 1\n#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL\n#define __SIZEOF_SIZE_T__ 8\n#define __CONSTANT_CFSTRINGS__ 1\n#define __SIG_ATOMIC_WIDTH__ 32\n#define __FLT64X_HAS_INFINITY__ 1\n#define __ARM_ALIGN_MAX_PWR 28\n#define __BFLT16_HAS_INFINITY__ 1\n#define __SIZEOF_WINT_T__ 4\n#define __LDBL_DECIMAL_DIG__ 17\n#define __LONG_LONG_WIDTH__ 64\n#define __FLT32_MAX_EXP__ 128\n#define __ARM_FP16_FORMAT_IEEE 1\n#define __builtin_infq __builtin_inff128\n#define __FLT_MIN_EXP__ (-125)\n#define __FLT32X_MIN_EXP__ (-1021)\n#define __INT_FAST64_TYPE__ long long int\n#define __ARM_FP16_ARGS 1\n#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __DBL_DECIMAL_DIG__ 17\n#define __FP_FAST_FMAF 1\n#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __FP_FAST_FMAL 1\n#define __BFLT16_HAS_DENORM__ 1\n#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64\n#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16\n#define __FLT64X_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __SIZEOF_POINTER__ 8\n#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128\n#define __LP64__ 1\n#define __DBL_HAS_QUIET_NAN__ 1\n#define __FLT_EVAL_METHOD_C99__ 0\n#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x\n#define __DECIMAL_BID_FORMAT__ 1\n#define __FLT64_MIN_EXP__ (-1021)\n#define __arm_in(...) [[__extension__ arm::in(__VA_ARGS__)]]\n#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __aarch64__ 1\n#define __FLT64_MIN_10_EXP__ (-307)\n#define __INT_FAST64_WIDTH__ 64\n#define __FLT64X_DECIMAL_DIG__ 36\n#define __DEC128_MIN__ 1E-6143DL\n#define __REGISTER_PREFIX__ \n#define __UINT16_MAX__ 0xffff\n#define __INTMAX_WIDTH__ 64\n#define __GXX_ABI_VERSION 1021\n#define __AARCH64EL__ 1\n#define __UINT8_TYPE__ unsigned char\n#define __FLT_DIG__ 6\n#define __NO_INLINE__ 1\n#define __arm_out(...) [[__extension__ arm::out(__VA_ARGS__)]]\n#define __DEC_EVAL_METHOD__ 2\n#define __FLT_MANT_DIG__ 24\n#define __FLT16_MIN_10_EXP__ (-4)\n#define __VERSION__ \"16.2.0\"\n#define __UINT64_C(c) c ## ULL\n#define __ARM_FEATURE_QRDMX 1\n#define __DEC64X_MIN__ 1E-6143D64x\n#define __INT_LEAST32_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_INT_LOCK_FREE 2\n#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x\n#define __FLT128_MAX_EXP__ 16384\n#define __FLT32_MANT_DIG__ 24\n#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __DEC128_MAX_EXP__ 6145\n#define __FLT16_MAX_EXP__ 16\n#define __BIGGEST_ALIGNMENT__ 16\n#define __INT32_C(c) c\n#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16\n#define __FLT128_HAS_DENORM__ 1\n#define __FLT128_DIG__ 33\n#define __SCHAR_WIDTH__ 8\n#define __DEC64_EPSILON__ 1E-15DD\n#define __ORDER_PDP_ENDIAN__ 3412\n#define __DEC128_MIN_EXP__ (-6142)\n#define __INT_FAST32_TYPE__ int\n#define __UINT_LEAST16_TYPE__ short unsigned int\n#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 150000\n#define __UINT64_MAX__ 0xffffffffffffffffULL\n#define __FLT_IS_IEC_60559__ 1\n#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"\n#define __FLT64X_DIG__ 33\n#define __ARM_FEATURE_FMA 1\n#define __INT8_TYPE__ signed char\n#define __GCC_ASM_FLAG_OUTPUTS__ 1\n#define __arm64__ 1\n#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1\n#define __BFLT16_HAS_QUIET_NAN__ 1\n#define __FLT_RADIX__ 2\n#define __INT_LEAST16_TYPE__ short int\n#define __ARM_ARCH_PROFILE 65\n#define __LDBL_EPSILON__ 2.22044604925031308084726333618164062e-16L\n#define __UINTMAX_C(c) c ## UL\n#define __DEC64X_EPSILON__ 1E-33D64x\n#define __ARM_PCS_AAPCS64 1\n#define __builtin_copysignq __builtin_copysignf128\n#define __SIG_ATOMIC_MAX__ 0x7fffffff\n#define __INT64_MAX__ 0x7fffffffffffffffLL\n#define __INT_LEAST64_WIDTH__ 64\n#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2\n#define __SIZEOF_PTRDIFF_T__ 8\n#define __arm64 1\n#define __ATOMIC_RELAXED 0\n#define __BFLT16_IS_IEC_60559__ 0\n#define __FLT32_HAS_INFINITY__ 1\n#define __SIZEOF_LONG__ 8\n#define __FLT64_IS_IEC_60559__ 1\n#define __FLT16_IS_IEC_60559__ 1\n#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF\n#define __STDC_EMBED_FOUND__ 1\n#define __INT_FAST16_MAX__ 0x7fff\n#define __GCC_CONSTRUCTIVE_SIZE 64\n#define __FLT64_DIG__ 15\n#define __UINT_FAST32_MAX__ 0xffffffffU\n#define __UINT_LEAST64_TYPE__ long long unsigned int\n#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16\n#define __FLT_HAS_QUIET_NAN__ 1\n#define __FLT_MAX_10_EXP__ 38\n#define __LONG_MAX__ 0x7fffffffffffffffL\n#define __FLT64X_HAS_DENORM__ 1\n#define __FLT_HAS_INFINITY__ 1\n#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"\n#define __DBL_HAS_DENORM__ 1\n#define __UINT_FAST16_TYPE__ short unsigned int\n#define __DEC64_MAX__ 9.999999999999999E384DD\n#define __FLT32X_HAS_QUIET_NAN__ 1\n#define __CHAR16_TYPE__ short unsigned int\n#define __PRAGMA_REDEFINE_EXTNAME 1\n#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x\n#define __BITINT_MAXWIDTH__ 65535\n#define __INT_LEAST16_MAX__ 0x7fff\n#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __DEC64_MANT_DIG__ 16\n#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32\n#define __INT_LEAST64_TYPE__ long long int\n#define __INT16_TYPE__ short int\n#define __INT_LEAST8_TYPE__ signed char\n#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __STDC_VERSION__ 202311L\n#define __DEC32_MAX_EXP__ 97\n#define __INT_FAST8_MAX__ 0x7f\n#define __ARM_ARCH 8\n#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __INTPTR_MAX__ 0x7fffffffffffffffL\n#define __arm_inout(...) [[__extension__ arm::inout(__VA_ARGS__)]]\n#define __arm_streaming [[__extension__ arm::streaming]]\n#define __FLT64_HAS_QUIET_NAN__ 1\n#define __ARM_FEATURE_BTI 1\n#define __FLT64X_MIN_EXP__ (-16381)\n#define __FLT32_MIN_10_EXP__ (-37)\n#define __FLT32X_DIG__ 15\n#define __UINT16_C(c) c\n#define __PTRDIFF_WIDTH__ 64\n#define __INT_FAST16_WIDTH__ 16\n#define __FLT64_HAS_INFINITY__ 1\n#define __FLT64X_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __FLT16_HAS_INFINITY__ 1\n#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)\n#define __FLT16_MANT_DIG__ 11\n#define __INTPTR_TYPE__ long int\n#define __UINT16_TYPE__ short unsigned int\n#define __WCHAR_TYPE__ int\n#define __pic__ 2\n#define __UINTPTR_MAX__ 0xffffffffffffffffUL\n#define __ARM_ARCH_8A 1\n#define __LDBL_HAS_INFINITY__ 1\n#define __ARM_FEATURE_UNALIGNED 1\n#define __FLT32_DECIMAL_DIG__ 9\n#define __INT_FAST64_MAX__ 0x7fffffffffffffffLL\n#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __FLT64X_MAX_EXP__ 16384\n#define __UINT_FAST64_TYPE__ long long unsigned int\n#define __DEC64X_MANT_DIG__ 34\n#define __BFLT16_MIN_EXP__ (-125)\n#define __INT_MAX__ 0x7fffffff\n#define __INT64_TYPE__ long long int\n#define __FLT_MAX_EXP__ 128\n#define __ORDER_BIG_ENDIAN__ 4321\n#define __DBL_MANT_DIG__ 53\n#define __BFLT16_MANT_DIG__ 8\n#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2\n#define __FP_FAST_FMAF32 1\n#define __WINT_TYPE__ int\n#define __UINT_LEAST32_TYPE__ unsigned int\n#define __SIZEOF_SHORT__ 2\n#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __LDBL_MIN_EXP__ (-1021)\n#define __GCC_ATOMIC_BOOL_LOCK_FREE 2\n#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __DEC64X_MIN_EXP__ (-6142)\n#define __LITTLE_ENDIAN__ 1\n#define __WINT_WIDTH__ 32\n#define __FP_FAST_FMAF64 1\n#define __INT_LEAST8_MAX__ 0x7f\n#define __FLT32X_MAX_10_EXP__ 308\n#define __SIZEOF_INT128__ 16\n#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16\n#define __LDBL_MAX_10_EXP__ 308\n#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)\n#define __INT_LEAST32_TYPE__ int\n#define __FLT32_MIN_EXP__ (-125)\n#define _LP64 1\n#define __UINT8_C(c) c\n#define __FLT64_MAX_EXP__ 1024\n#define __SIZEOF_WCHAR_T__ 4\n#define __UINT64_TYPE__ long long unsigned int\n#define __ARM_FEATURE_CRC32 1\n#define __ARM_NEON 1\n#define __MACH__ 1\n#define __FLT128_HAS_QUIET_NAN__ 1\n#define __INTMAX_MAX__ 0x7fffffffffffffffL\n#define __UINT_FAST8_TYPE__ unsigned char\n#define __INT_FAST8_TYPE__ signed char\n#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x\n#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64\n#define __arm_preserves(...) [[__extension__ arm::preserves(__VA_ARGS__)]]\n#define __GNUC_STDC_INLINE__ 1\n#define __FLT64_HAS_DENORM__ 1\n#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32\n#define __FLT16_HAS_DENORM__ 1\n#define __STDC_UTF_32__ 1\n#define __INT_FAST8_WIDTH__ 8\n#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __ARM_ALIGN_MAX_STACK_PWR 16\n#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221372e-324L\n#define __GCC_DESTRUCTIVE_SIZE 256\n#define __ARM_FEATURE_PAUTH 1\n#define __FLT32_DIG__ 6\n#define __UINT32_C(c) c ## U\n#define __WINT_MIN__ (-__WINT_MAX__ - 1)\n#define __FLT128_IS_IEC_60559__ 1\n#define __INT8_MAX__ 0x7f\n#define __LONG_WIDTH__ 64\n#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)\n#define __PIC__ 2\n#define __INT32_MAX__ 0x7fffffff\n#define __BFLT16_MAX_10_EXP__ 38\n#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __CHAR32_TYPE__ unsigned int\n#define __ARM_FEATURE_NUMERIC_MAXMIN 1\n#define __INT32_TYPE__ int\n#define __SIZEOF_DOUBLE__ 8\n#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64\n#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F\n#define __INT_LEAST32_WIDTH__ 32\n#define __SIZEOF_FLOAT__ 4\n#define __ARM_FEATURE_COMPLEX 1\n#define __builtin_fabsq __builtin_fabsf128\n#define __ATOMIC_CONSUME 1\n#define __SIZE_MAX__ 0xffffffffffffffffUL\n#define __GNUC_MINOR__ 2\n#define __UINTMAX_MAX__ 0xffffffffffffffffUL\n#define __DEC32_MANT_DIG__ 7\n#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x\n#define __arm_locally_streaming [[__extension__ arm::locally_streaming]]\n#define __DBL_MAX_10_EXP__ 308\n#define __INT16_C(c) c\n#define __ARM_ARCH_ISA_A64 1\n#define __ATOMIC_RELEASE 3\n#define __STDC__ 1\n#define __PTRDIFF_TYPE__ long int\n#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1\n#define __UINT32_TYPE__ unsigned int\n#define __FLT32X_MIN_10_EXP__ (-307)\n#define __UINTPTR_TYPE__ long unsigned int\n#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD\n#define __DEC128_MANT_DIG__ 34\n#define __LDBL_MIN_10_EXP__ (-307)\n#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128\n#define __SIZEOF_LONG_LONG__ 8\n#define __FP_FAST_FMAF32x 1\n#define __FLT128_DECIMAL_DIG__ 36\n#define __GCC_ATOMIC_LLONG_LOCK_FREE 2\n#define __FLT_DECIMAL_DIG__ 9\n#define __UINT_FAST16_MAX__ 0xffff\n#define __LDBL_NORM_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT_MIN_10_EXP__ (-37)\n#define __GCC_ATOMIC_SHORT_LOCK_FREE 2\n#define __ORDER_LITTLE_ENDIAN__ 1234\n#define __WCHAR_MAX__ 0x7fffffff\n#define __UINT_LEAST32_MAX__ 0xffffffffU\n#define __ATOMIC_ACQ_REL 4\n", + "flags": "", + "compiler": "gcc-16 (Homebrew GCC 16.2.0) 16.2.0", + "target": "aarch64-apple-darwin24", + "about": "Nothing asked for. This is what an empty file already knows" + }, + "elsewhere": { + "text": "#define __DBL_MIN_EXP__ (-1021)\n#define __LDBL_MANT_DIG__ 64\n#define __UINT_LEAST16_MAX__ 0xffff\n#define __FLT16_HAS_QUIET_NAN__ 1\n#define __ATOMIC_ACQUIRE 2\n#define __WCHAR_MAX__ 0x7fffffff\n#define __FLT128_MAX_10_EXP__ 4932\n#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n#define __GCC_IEC_559_COMPLEX 2\n#define __UINT_LEAST8_TYPE__ unsigned char\n#define __SIZEOF_FLOAT80__ 16\n#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16\n#define __INTMAX_C(c) c ## L\n#define __CHAR_BIT__ 8\n#define __UINT8_MAX__ 0xff\n#define __SCHAR_WIDTH__ 8\n#define __WINT_MAX__ 0xffffffffU\n#define __FLT32_MIN_EXP__ (-125)\n#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_MIN_10_EXP__ (-37)\n#define __ORDER_LITTLE_ENDIAN__ 1234\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1\n#define __GCC_ATOMIC_CHAR_LOCK_FREE 2\n#define __GCC_IEC_559 2\n#define __FLT32X_DECIMAL_DIG__ 17\n#define __FLT_EVAL_METHOD__ 0\n#define __FLT64_DECIMAL_DIG__ 17\n#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2\n#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL\n#define __SIG_ATOMIC_TYPE__ int\n#define __DBL_MIN_10_EXP__ (-307)\n#define __FINITE_MATH_ONLY__ 0\n#define __FLT32X_MAX_EXP__ 1024\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1\n#define __FLT32_HAS_DENORM__ 1\n#define __UINT_FAST8_MAX__ 0xff\n#define __FLT32_MAX_10_EXP__ 38\n#define __DEC64_MAX_EXP__ 385\n#define __INT8_C(c) c\n#define __INT_LEAST8_WIDTH__ 8\n#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL\n#define __SHRT_MAX__ 0x7fff\n#define __LDBL_MAX__ 1.18973149535723176502126385303097021e+4932L\n#define __FLT64X_MAX_10_EXP__ 4932\n#define __BFLT16_MAX_10_EXP__ 38\n#define __BFLT16_MAX_EXP__ 128\n#define __LDBL_IS_IEC_60559__ 1\n#define __FLT64X_HAS_QUIET_NAN__ 1\n#define __UINT_LEAST8_MAX__ 0xff\n#define __GCC_ATOMIC_BOOL_LOCK_FREE 2\n#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128\n#define __UINTMAX_TYPE__ long unsigned int\n#define __BFLT16_DECIMAL_DIG__ 4\n#define __linux 1\n#define __DEC32_EPSILON__ 1E-6DF\n#define __FLT_EVAL_METHOD_TS_18661_3__ 0\n#define __UINT32_MAX__ 0xffffffffU\n#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)\n#define __FLT128_MIN_EXP__ (-16381)\n#define __DEC64X_MAX_EXP__ 6145\n#define __WINT_MIN__ 0U\n#define __FLT128_MIN_10_EXP__ (-4931)\n#define __FLT32X_IS_IEC_60559__ 1\n#define __INT_LEAST16_WIDTH__ 16\n#define __SCHAR_MAX__ 0x7f\n#define __FLT128_MANT_DIG__ 113\n#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)\n#define __INT64_C(c) c ## L\n#define __GCC_ATOMIC_POINTER_LOCK_FREE 2\n#define __ATOMIC_SEQ_CST 5\n#define __unix 1\n#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL\n#define __FLT32X_MANT_DIG__ 53\n#define __FLT64X_EPSILON__ 1.08420217248550443400745280086994171e-19F64x\n#define __STDC_HOSTED__ 1\n#define __DEC64_MIN_EXP__ (-382)\n#define __DBL_DIG__ 15\n#define __STDC_EMBED_EMPTY__ 2\n#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n#define __SHRT_WIDTH__ 16\n#define __FLT32_IS_IEC_60559__ 1\n#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L\n#define __STDC_UTF_16__ 1\n#define __DBL_IS_IEC_60559__ 1\n#define __DEC32_MAX__ 9.999999E96DF\n#define __CHAR8_TYPE__ unsigned char\n#define __FLT64X_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951F64x\n#define __FLT32X_HAS_INFINITY__ 1\n#define __unix__ 1\n#define __INT_WIDTH__ 32\n#define __STDC_IEC_559__ 1\n#define __STDC_ISO_10646__ 201706L\n#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2\n#define __DECIMAL_DIG__ 21\n#define __STDC_IEC_559_COMPLEX__ 1\n#define __gnu_linux__ 1\n#define __FLT64X_MIN_10_EXP__ (-4931)\n#define __LDBL_HAS_QUIET_NAN__ 1\n#define __FLT16_MIN_EXP__ (-13)\n#define __FLT64_MANT_DIG__ 53\n#define __FLT64X_MANT_DIG__ 64\n#define __BFLT16_DIG__ 2\n#define __GNUC__ 16\n#define __MMX__ 1\n#define __FLT_HAS_DENORM__ 1\n#define __SIZEOF_LONG_DOUBLE__ 16\n#define __LDBL_DIG__ 18\n#define __BIGGEST_ALIGNMENT__ 16\n#define __FLT64_MAX_10_EXP__ 308\n#define __BFLT16_IS_IEC_60559__ 0\n#define __FLT16_MAX_10_EXP__ 4\n#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __INT_FAST32_MAX__ 0x7fffffffffffffffL\n#define __DBL_HAS_INFINITY__ 1\n#define __INT64_MAX__ 0x7fffffffffffffffL\n#define __SIZEOF_FLOAT__ 4\n#define __HAVE_SPECULATION_SAFE_VALUE 1\n#define __DEC32_MIN_EXP__ (-94)\n#define __INTPTR_WIDTH__ 64\n#define __UINT_LEAST32_MAX__ 0xffffffffU\n#define __FLT32X_HAS_DENORM__ 1\n#define __INT_FAST16_TYPE__ long int\n#define __MMX_WITH_SSE__ 1\n#define __LDBL_HAS_DENORM__ 1\n#define __SEG_GS 1\n#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16\n#define __FLT128_HAS_INFINITY__ 1\n#define __DEC32_MIN__ 1E-95DF\n#define __DBL_MAX_EXP__ 1024\n#define __WCHAR_WIDTH__ 32\n#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __DEC128_EPSILON__ 1E-33DL\n#define __FLT16_DECIMAL_DIG__ 5\n#define __SSE2_MATH__ 1\n#define __ATOMIC_HLE_RELEASE 131072\n#define __PTRDIFF_MAX__ 0x7fffffffffffffffL\n#define __amd64 1\n#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x\n#define __ATOMIC_HLE_ACQUIRE 65536\n#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL\n#define __SIZEOF_SIZE_T__ 8\n#define __BFLT16_HAS_INFINITY__ 1\n#define __FLT64X_MIN_EXP__ (-16381)\n#define __SIZEOF_WINT_T__ 4\n#define __LONG_LONG_WIDTH__ 64\n#define __FLT32_MAX_EXP__ 128\n#define __GXX_ABI_VERSION 1021\n#define __FLT_MIN_EXP__ (-125)\n#define __GCC_HAVE_DWARF2_CFI_ASM 1\n#define __INT16_MAX__ 0x7fff\n#define __x86_64 1\n#define __INT_FAST64_TYPE__ long int\n#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_HAS_DENORM__ 1\n#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64\n#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16\n#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128\n#define __FLT64X_NORM_MAX__ 1.18973149535723176502126385303097021e+4932F64x\n#define __SIZEOF_POINTER__ 8\n#define __SIZE_TYPE__ long unsigned int\n#define __LP64__ 1\n#define __DBL_HAS_QUIET_NAN__ 1\n#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x\n#define __LDBL_MAX_EXP__ 16384\n#define __DECIMAL_BID_FORMAT__ 1\n#define __FLT64_MIN_EXP__ (-1021)\n#define __FLT64_MIN_10_EXP__ (-307)\n#define __FLT16_MIN_10_EXP__ (-4)\n#define __FLT64X_DECIMAL_DIG__ 21\n#define __DEC128_MIN__ 1E-6143DL\n#define __REGISTER_PREFIX__ \n#define __UINT16_MAX__ 0xffff\n#define __DBL_HAS_DENORM__ 1\n#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32\n#define __UINT8_TYPE__ unsigned char\n#define __FLT_DIG__ 6\n#define __NO_INLINE__ 1\n#define __DEC_EVAL_METHOD__ 2\n#define __FLT_MANT_DIG__ 24\n#define __LDBL_DECIMAL_DIG__ 21\n#define __VERSION__ \"16.2.0\"\n#define __UINT64_C(c) c ## UL\n#define __DEC64X_MIN__ 1E-6143D64x\n#define _STDC_PREDEF_H 1\n#define __INT_LEAST32_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_INT_LOCK_FREE 2\n#define __FLT128_MAX_EXP__ 16384\n#define __FLT32_MANT_DIG__ 24\n#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __FLT32X_MIN_EXP__ (-1021)\n#define __STDC_IEC_60559_COMPLEX__ 201404L\n#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16\n#define __FLT128_HAS_DENORM__ 1\n#define __FLT32_DECIMAL_DIG__ 9\n#define __FLT128_DIG__ 33\n#define __INT32_C(c) c\n#define __DEC64_EPSILON__ 1E-15DD\n#define __ORDER_PDP_ENDIAN__ 3412\n#define __DEC128_MIN_EXP__ (-6142)\n#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL\n#define __INT_FAST32_TYPE__ long int\n#define __UINT_LEAST16_TYPE__ short unsigned int\n#define __DEC64X_MANT_DIG__ 34\n#define __DEC128_MAX_EXP__ 6145\n#define unix 1\n#define __UINT64_MAX__ 0xffffffffffffffffUL\n#define __FLT_IS_IEC_60559__ 1\n#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"\n#define __FLT64X_DIG__ 18\n#define __INT8_TYPE__ signed char\n#define __ELF__ 1\n#define __GCC_ASM_FLAG_OUTPUTS__ 1\n#define __UINT32_TYPE__ unsigned int\n#define __BFLT16_HAS_QUIET_NAN__ 1\n#define __FLT_RADIX__ 2\n#define __INT_LEAST16_TYPE__ short int\n#define __LDBL_EPSILON__ 1.08420217248550443400745280086994171e-19L\n#define __UINTMAX_C(c) c ## UL\n#define __DEC64X_EPSILON__ 1E-33D64x\n#define __FLT16_DIG__ 3\n#define __SSE_MATH__ 1\n#define __k8 1\n#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x\n#define __SIG_ATOMIC_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2\n#define __USER_LABEL_PREFIX__ \n#define __STDC_IEC_60559_BFP__ 201404L\n#define __SIZEOF_PTRDIFF_T__ 8\n#define __FLT64X_HAS_INFINITY__ 1\n#define __FLT32_HAS_INFINITY__ 1\n#define __SIZEOF_LONG__ 8\n#define __FLT64_IS_IEC_60559__ 1\n#define __x86_64__ 1\n#define __FLT16_IS_IEC_60559__ 1\n#define __FLT16_MAX_EXP__ 16\n#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF\n#define __STDC_EMBED_FOUND__ 1\n#define __INT_FAST16_MAX__ 0x7fffffffffffffffL\n#define __GCC_CONSTRUCTIVE_SIZE 64\n#define __FLT64_DIG__ 15\n#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL\n#define __UINT_LEAST64_TYPE__ long unsigned int\n#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16\n#define __FLT_HAS_QUIET_NAN__ 1\n#define __FLT_MAX_10_EXP__ 38\n#define __LONG_MAX__ 0x7fffffffffffffffL\n#define __FLT64X_HAS_DENORM__ 1\n#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL\n#define __FLT_HAS_INFINITY__ 1\n#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"\n#define __UINT_FAST16_TYPE__ long unsigned int\n#define __DEC64_MAX__ 9.999999999999999E384DD\n#define __STDC_EMBED_NOT_FOUND__ 0\n#define __INT_FAST32_WIDTH__ 64\n#define __CHAR16_TYPE__ short unsigned int\n#define __PRAGMA_REDEFINE_EXTNAME 1\n#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x\n#define __SIZE_WIDTH__ 64\n#define __SEG_FS 1\n#define __BITINT_MAXWIDTH__ 65535\n#define __INT_LEAST16_MAX__ 0x7fff\n#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __DEC64_MANT_DIG__ 16\n#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32\n#define __SIG_ATOMIC_WIDTH__ 32\n#define __INT_LEAST64_TYPE__ long int\n#define __INT16_TYPE__ short int\n#define __INT_LEAST8_TYPE__ signed char\n#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128\n#define __STDC_VERSION__ 202311L\n#define __SIZEOF_INT__ 4\n#define __DEC32_MAX_EXP__ 97\n#define __INT_FAST8_MAX__ 0x7f\n#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __INTPTR_MAX__ 0x7fffffffffffffffL\n#define linux 1\n#define __FLT64_HAS_QUIET_NAN__ 1\n#define __FLT32_MIN_10_EXP__ (-37)\n#define __FLT32X_DIG__ 15\n#define __UINT16_C(c) c\n#define __PTRDIFF_WIDTH__ 64\n#define __INT_FAST16_WIDTH__ 64\n#define __FLT64_HAS_INFINITY__ 1\n#define __FLT64X_MAX__ 1.18973149535723176502126385303097021e+4932F64x\n#define __FLT16_HAS_INFINITY__ 1\n#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)\n#define __code_model_small__ 1\n#define __GCC_ATOMIC_LONG_LOCK_FREE 2\n#define __DEC32_MANT_DIG__ 7\n#define __FLT16_MANT_DIG__ 11\n#define __k8__ 1\n#define __INTPTR_TYPE__ long int\n#define __UINT16_TYPE__ short unsigned int\n#define __WCHAR_TYPE__ int\n#define __UINTPTR_MAX__ 0xffffffffffffffffUL\n#define __INT_FAST64_WIDTH__ 64\n#define __LDBL_HAS_INFINITY__ 1\n#define __INT_FAST64_MAX__ 0x7fffffffffffffffL\n#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1\n#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __FLT64X_MAX_EXP__ 16384\n#define __UINT_FAST64_TYPE__ long unsigned int\n#define __BFLT16_MIN_EXP__ (-125)\n#define __INT_MAX__ 0x7fffffff\n#define __linux__ 1\n#define __INT64_TYPE__ long int\n#define __FLT_MAX_EXP__ 128\n#define __ORDER_BIG_ENDIAN__ 4321\n#define __DBL_MANT_DIG__ 53\n#define __SIZEOF_FLOAT128__ 16\n#define __BFLT16_MANT_DIG__ 8\n#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2\n#define __DEC64_MIN__ 1E-383DD\n#define __WINT_TYPE__ unsigned int\n#define __UINT_LEAST32_TYPE__ unsigned int\n#define __SIZEOF_SHORT__ 2\n#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __SSE__ 1\n#define __LDBL_MIN_EXP__ (-16381)\n#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __DEC64X_MIN_EXP__ (-6142)\n#define __amd64__ 1\n#define __WINT_WIDTH__ 32\n#define __INT_LEAST8_MAX__ 0x7f\n#define __INT_LEAST64_WIDTH__ 64\n#define __FLT32X_MAX_10_EXP__ 308\n#define __SIZEOF_INT128__ 16\n#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16\n#define __FLT64X_IS_IEC_60559__ 1\n#define __LDBL_MAX_10_EXP__ 4932\n#define __ATOMIC_RELAXED 0\n#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)\n#define __INT_LEAST32_TYPE__ int\n#define _LP64 1\n#define __UINT8_C(c) c\n#define __FLT64_MAX_EXP__ 1024\n#define __SIZEOF_WCHAR_T__ 4\n#define __UINT64_TYPE__ long unsigned int\n#define __GNUC_PATCHLEVEL__ 0\n#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __FLT128_HAS_QUIET_NAN__ 1\n#define __INTMAX_MAX__ 0x7fffffffffffffffL\n#define __INT_FAST8_TYPE__ signed char\n#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x\n#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64\n#define __GNUC_STDC_INLINE__ 1\n#define __FLT64_HAS_DENORM__ 1\n#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32\n#define __FLT16_HAS_DENORM__ 1\n#define __DBL_DECIMAL_DIG__ 17\n#define __STDC_UTF_32__ 1\n#define __INT_FAST8_WIDTH__ 8\n#define __FXSR__ 1\n#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __GCC_DESTRUCTIVE_SIZE 64\n#define __INTMAX_WIDTH__ 64\n#define __FLT32_DIG__ 6\n#define __UINT32_C(c) c ## U\n#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F\n#define __FLT128_IS_IEC_60559__ 1\n#define __INT8_MAX__ 0x7f\n#define __LONG_WIDTH__ 64\n#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)\n#define __INT32_MAX__ 0x7fffffff\n#define __UINT_FAST32_TYPE__ long unsigned int\n#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __CHAR32_TYPE__ unsigned int\n#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __SSE2__ 1\n#define __INT32_TYPE__ int\n#define __SIZEOF_DOUBLE__ 8\n#define __FLT_MIN_10_EXP__ (-37)\n#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64\n#define __INT_LEAST32_WIDTH__ 32\n#define __INTMAX_TYPE__ long int\n#define __FLT32X_HAS_QUIET_NAN__ 1\n#define __ATOMIC_CONSUME 1\n#define __GNUC_MINOR__ 2\n#define __UINTMAX_MAX__ 0xffffffffffffffffUL\n#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x\n#define __DBL_MAX_10_EXP__ 308\n#define __LDBL_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951L\n#define __INT16_C(c) c\n#define __ATOMIC_RELEASE 3\n#define __STDC__ 1\n#define __PTRDIFF_TYPE__ long int\n#define __FLT32X_MIN_10_EXP__ (-307)\n#define __UINTPTR_TYPE__ long unsigned int\n#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD\n#define __DEC128_MANT_DIG__ 34\n#define __LDBL_MIN_10_EXP__ (-4931)\n#define __SIZEOF_LONG_LONG__ 8\n#define __FLT128_DECIMAL_DIG__ 36\n#define __GCC_ATOMIC_LLONG_LOCK_FREE 2\n#define __FLT32_HAS_QUIET_NAN__ 1\n#define __FLT_DECIMAL_DIG__ 9\n#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL\n#define __LDBL_NORM_MAX__ 1.18973149535723176502126385303097021e+4932L\n#define __GCC_ATOMIC_SHORT_LOCK_FREE 2\n#define __SIZE_MAX__ 0xffffffffffffffffUL\n#define __UINT_FAST8_TYPE__ unsigned char\n#define __ATOMIC_ACQ_REL 4\n", + "flags": "", + "compiler": "gcc 16.2.0 (Compiler-Explorer-Build-gcc--binutils-2.44)", + "target": "x86_64-linux-gnu", + "about": "The same GCC release, built for x86-64 Linux by other people" + }, + "optimized": { + "text": "#define __builtin_nanq __builtin_nanf128\n#define __DBL_MIN_EXP__ (-1021)\n#define __UINT_LEAST16_MAX__ 0xffff\n#define __ARM_SIZEOF_WCHAR_T 4\n#define __ATOMIC_ACQUIRE 2\n#define __FLT128_MAX_10_EXP__ 4932\n#define __ARM_STATE_ZT0 1\n#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n#define __GCC_IEC_559_COMPLEX 2\n#define __UINT_LEAST8_TYPE__ unsigned char\n#define __INTMAX_C(c) c ## L\n#define __CHAR_BIT__ 8\n#define __UINT8_MAX__ 0xff\n#define __USER_LABEL_PREFIX__ _\n#define __WINT_MAX__ 0x7fffffff\n#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_MIN_10_EXP__ (-37)\n#define __arm_streaming_compatible [[__extension__ arm::streaming_compatible]]\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1\n#define __GCC_ATOMIC_CHAR_LOCK_FREE 2\n#define __ARM_FEATURE_ATOMICS 1\n#define __GCC_IEC_559 2\n#define __FLT32X_DECIMAL_DIG__ 17\n#define __builtin_nansq __builtin_nansf128\n#define __FLT_EVAL_METHOD__ 0\n#define __FLT64_DECIMAL_DIG__ 17\n#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2\n#define __INTPTR_WIDTH__ 64\n#define __UINT_FAST32_TYPE__ unsigned int\n#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL\n#define __SIG_ATOMIC_TYPE__ int\n#define __ARM_FEATURE_RCPC 1\n#define __DBL_MIN_10_EXP__ (-307)\n#define __FINITE_MATH_ONLY__ 0\n#define __PTRDIFF_MAX__ 0x7fffffffffffffffL\n#define __FLT32X_MAX_EXP__ 1024\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1\n#define __GNUC_PATCHLEVEL__ 0\n#define __FLT32_HAS_DENORM__ 1\n#define __UINT_FAST8_MAX__ 0xff\n#define __FLT32_MAX_10_EXP__ 38\n#define __DEC64_MAX_EXP__ 385\n#define __INT8_C(c) c\n#define __ARM_64BIT_STATE 1\n#define __INT_LEAST8_WIDTH__ 8\n#define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL\n#define __SHRT_MAX__ 0x7fff\n#define __ARM_FEATURE_IDIV 1\n#define __FLT64X_MAX_10_EXP__ 4932\n#define __BFLT16_MAX_EXP__ 128\n#define __ARM_NEON_SVE_BRIDGE 1\n#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __LDBL_IS_IEC_60559__ 1\n#define __ARM_FP 14\n#define __FLT64X_IS_IEC_60559__ 1\n#define __FLT64X_HAS_QUIET_NAN__ 1\n#define __UINT_LEAST8_MAX__ 0xff\n#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128\n#define __APPLE_CC__ 1\n#define __UINTMAX_TYPE__ long unsigned int\n#define __BFLT16_DECIMAL_DIG__ 4\n#define __DEC32_EPSILON__ 1E-6DF\n#define __FLT_EVAL_METHOD_TS_18661_3__ 0\n#define __OPTIMIZE__ 1\n#define __UINT32_MAX__ 0xffffffffU\n#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)\n#define __AARCH64_CMODEL_SMALL__ 1\n#define __LDBL_MAX_EXP__ 1024\n#define __STDC_EMBED_NOT_FOUND__ 0\n#define __INT_FAST32_WIDTH__ 32\n#define __FLT128_MIN_EXP__ (-16381)\n#define __DEC64X_MAX_EXP__ 6145\n#define __FLT128_MIN_10_EXP__ (-4931)\n#define __FLT32X_IS_IEC_60559__ 1\n#define __INT_LEAST16_WIDTH__ 16\n#define __SCHAR_MAX__ 0x7f\n#define __FLT128_MANT_DIG__ 113\n#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)\n#define __INT64_C(c) c ## LL\n#define __GCC_ATOMIC_POINTER_LOCK_FREE 2\n#define __ATOMIC_SEQ_CST 5\n#define __SIZEOF_INT__ 4\n#define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL\n#define __ARM_FEATURE_CLZ 1\n#define __ARM_STATE_ZA 1\n#define __FLT32X_MANT_DIG__ 53\n#define __LDBL_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT64X_EPSILON__ 1.92592994438723585305597794258492732e-34F64x\n#define __STDC_HOSTED__ 1\n#define __DEC64_MIN_EXP__ (-382)\n#define __DBL_DIG__ 15\n#define __STDC_EMBED_EMPTY__ 2\n#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n#define __SHRT_WIDTH__ 16\n#define __DEC64_MIN__ 1E-383DD\n#define __FLT32_IS_IEC_60559__ 1\n#define __LDBL_MIN__ 2.22507385850720138309023271733240406e-308L\n#define __STDC_UTF_16__ 1\n#define __DBL_IS_IEC_60559__ 1\n#define __DEC32_MAX__ 9.999999E96DF\n#define __FLT16_HAS_QUIET_NAN__ 1\n#define __CHAR8_TYPE__ unsigned char\n#define __strong \n#define __ARM_SIZEOF_MINIMAL_ENUM 4\n#define __FLT64X_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F64x\n#define __FP_FAST_FMA 1\n#define __FLT32X_HAS_INFINITY__ 1\n#define __FLT16_DIG__ 3\n#define __INT_WIDTH__ 32\n#define __BFLT16_DIG__ 2\n#define __SIZE_WIDTH__ 64\n#define __ARM_FEATURE_JCVT 1\n#define __APPLE__ 1\n#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2\n#define __DECIMAL_DIG__ 17\n#define __ARM_FEATURE_DOTPROD 1\n#define __INT16_MAX__ 0x7fff\n#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL\n#define __FLT64X_MIN_10_EXP__ (-4931)\n#define __LDBL_HAS_QUIET_NAN__ 1\n#define __FLT16_MIN_EXP__ (-13)\n#define __FLT64_MANT_DIG__ 53\n#define __LDBL_MANT_DIG__ 53\n#define __FLT64X_MANT_DIG__ 113\n#define __DYNAMIC__ 1\n#define __GNUC__ 16\n#define __FLT16_DECIMAL_DIG__ 5\n#define __FLT_HAS_DENORM__ 1\n#define __SIZEOF_LONG_DOUBLE__ 8\n#define __arm_new(...) [[__extension__ arm::new(__VA_ARGS__)]]\n#define __LDBL_DIG__ 15\n#define __SIZE_TYPE__ long unsigned int\n#define __FLT64_MAX_10_EXP__ 308\n#define __INTMAX_TYPE__ long int\n#define __FLT16_MAX_10_EXP__ 4\n#define __INT_FAST32_MAX__ 0x7fffffff\n#define __DBL_HAS_INFINITY__ 1\n#define __HAVE_SPECULATION_SAFE_VALUE 1\n#define __DEC32_MIN_EXP__ (-94)\n#define __builtin_huge_valq __builtin_huge_valf128\n#define __FLT32X_HAS_DENORM__ 1\n#define __INT_FAST16_TYPE__ short int\n#define __LDBL_HAS_DENORM__ 1\n#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16\n#define __FLT128_HAS_INFINITY__ 1\n#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL\n#define __DEC32_MIN__ 1E-95DF\n#define __weak \n#define __ARM_FEATURE_FRINT 1\n#define __DBL_MAX_EXP__ 1024\n#define __WCHAR_WIDTH__ 32\n#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __DEC128_EPSILON__ 1E-33DL\n#define __GCC_ATOMIC_LONG_LOCK_FREE 2\n#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16\n#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x\n#define __FLT32_HAS_QUIET_NAN__ 1\n#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL\n#define __SIZEOF_SIZE_T__ 8\n#define __CONSTANT_CFSTRINGS__ 1\n#define __SIG_ATOMIC_WIDTH__ 32\n#define __FLT64X_HAS_INFINITY__ 1\n#define __ARM_ALIGN_MAX_PWR 28\n#define __BFLT16_HAS_INFINITY__ 1\n#define __SIZEOF_WINT_T__ 4\n#define __LDBL_DECIMAL_DIG__ 17\n#define __LONG_LONG_WIDTH__ 64\n#define __FLT32_MAX_EXP__ 128\n#define __ARM_FP16_FORMAT_IEEE 1\n#define __builtin_infq __builtin_inff128\n#define __FLT_MIN_EXP__ (-125)\n#define __FLT32X_MIN_EXP__ (-1021)\n#define __INT_FAST64_TYPE__ long long int\n#define __ARM_FP16_ARGS 1\n#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __DBL_DECIMAL_DIG__ 17\n#define __FP_FAST_FMAF 1\n#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __FP_FAST_FMAL 1\n#define __BFLT16_HAS_DENORM__ 1\n#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64\n#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16\n#define __FLT64X_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __SIZEOF_POINTER__ 8\n#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128\n#define __LP64__ 1\n#define __DBL_HAS_QUIET_NAN__ 1\n#define __FLT_EVAL_METHOD_C99__ 0\n#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x\n#define __DECIMAL_BID_FORMAT__ 1\n#define __FLT64_MIN_EXP__ (-1021)\n#define __arm_in(...) [[__extension__ arm::in(__VA_ARGS__)]]\n#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __aarch64__ 1\n#define __FLT64_MIN_10_EXP__ (-307)\n#define __INT_FAST64_WIDTH__ 64\n#define __FLT64X_DECIMAL_DIG__ 36\n#define __DEC128_MIN__ 1E-6143DL\n#define __REGISTER_PREFIX__ \n#define __UINT16_MAX__ 0xffff\n#define __INTMAX_WIDTH__ 64\n#define __GXX_ABI_VERSION 1021\n#define __AARCH64EL__ 1\n#define __UINT8_TYPE__ unsigned char\n#define __FLT_DIG__ 6\n#define __arm_out(...) [[__extension__ arm::out(__VA_ARGS__)]]\n#define __DEC_EVAL_METHOD__ 2\n#define __FLT_MANT_DIG__ 24\n#define __FLT16_MIN_10_EXP__ (-4)\n#define __VERSION__ \"16.2.0\"\n#define __UINT64_C(c) c ## ULL\n#define __ARM_FEATURE_QRDMX 1\n#define __DEC64X_MIN__ 1E-6143D64x\n#define __INT_LEAST32_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_INT_LOCK_FREE 2\n#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x\n#define __FLT128_MAX_EXP__ 16384\n#define __FLT32_MANT_DIG__ 24\n#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __DEC128_MAX_EXP__ 6145\n#define __FLT16_MAX_EXP__ 16\n#define __BIGGEST_ALIGNMENT__ 16\n#define __INT32_C(c) c\n#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16\n#define __FLT128_HAS_DENORM__ 1\n#define __FLT128_DIG__ 33\n#define __SCHAR_WIDTH__ 8\n#define __DEC64_EPSILON__ 1E-15DD\n#define __ORDER_PDP_ENDIAN__ 3412\n#define __DEC128_MIN_EXP__ (-6142)\n#define __INT_FAST32_TYPE__ int\n#define __UINT_LEAST16_TYPE__ short unsigned int\n#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 150000\n#define __UINT64_MAX__ 0xffffffffffffffffULL\n#define __FLT_IS_IEC_60559__ 1\n#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"\n#define __FLT64X_DIG__ 33\n#define __ARM_FEATURE_FMA 1\n#define __INT8_TYPE__ signed char\n#define __GCC_ASM_FLAG_OUTPUTS__ 1\n#define __arm64__ 1\n#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1\n#define __BFLT16_HAS_QUIET_NAN__ 1\n#define __FLT_RADIX__ 2\n#define __INT_LEAST16_TYPE__ short int\n#define __ARM_ARCH_PROFILE 65\n#define __LDBL_EPSILON__ 2.22044604925031308084726333618164062e-16L\n#define __UINTMAX_C(c) c ## UL\n#define __DEC64X_EPSILON__ 1E-33D64x\n#define __ARM_PCS_AAPCS64 1\n#define __builtin_copysignq __builtin_copysignf128\n#define __SIG_ATOMIC_MAX__ 0x7fffffff\n#define __INT64_MAX__ 0x7fffffffffffffffLL\n#define __INT_LEAST64_WIDTH__ 64\n#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2\n#define __SIZEOF_PTRDIFF_T__ 8\n#define __arm64 1\n#define __ATOMIC_RELAXED 0\n#define __BFLT16_IS_IEC_60559__ 0\n#define __FLT32_HAS_INFINITY__ 1\n#define __SIZEOF_LONG__ 8\n#define __FLT64_IS_IEC_60559__ 1\n#define __FLT16_IS_IEC_60559__ 1\n#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF\n#define __STDC_EMBED_FOUND__ 1\n#define __INT_FAST16_MAX__ 0x7fff\n#define __GCC_CONSTRUCTIVE_SIZE 64\n#define __FLT64_DIG__ 15\n#define __UINT_FAST32_MAX__ 0xffffffffU\n#define __UINT_LEAST64_TYPE__ long long unsigned int\n#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16\n#define __FLT_HAS_QUIET_NAN__ 1\n#define __FLT_MAX_10_EXP__ 38\n#define __LONG_MAX__ 0x7fffffffffffffffL\n#define __FLT64X_HAS_DENORM__ 1\n#define __FLT_HAS_INFINITY__ 1\n#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"\n#define __DBL_HAS_DENORM__ 1\n#define __UINT_FAST16_TYPE__ short unsigned int\n#define __DEC64_MAX__ 9.999999999999999E384DD\n#define __FLT32X_HAS_QUIET_NAN__ 1\n#define __CHAR16_TYPE__ short unsigned int\n#define __PRAGMA_REDEFINE_EXTNAME 1\n#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x\n#define __BITINT_MAXWIDTH__ 65535\n#define __INT_LEAST16_MAX__ 0x7fff\n#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __DEC64_MANT_DIG__ 16\n#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32\n#define __INT_LEAST64_TYPE__ long long int\n#define __INT16_TYPE__ short int\n#define __INT_LEAST8_TYPE__ signed char\n#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __STDC_VERSION__ 202311L\n#define __DEC32_MAX_EXP__ 97\n#define __INT_FAST8_MAX__ 0x7f\n#define __ARM_ARCH 8\n#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __INTPTR_MAX__ 0x7fffffffffffffffL\n#define __arm_inout(...) [[__extension__ arm::inout(__VA_ARGS__)]]\n#define __arm_streaming [[__extension__ arm::streaming]]\n#define __FLT64_HAS_QUIET_NAN__ 1\n#define __ARM_FEATURE_BTI 1\n#define __FLT64X_MIN_EXP__ (-16381)\n#define __FLT32_MIN_10_EXP__ (-37)\n#define __FLT32X_DIG__ 15\n#define __UINT16_C(c) c\n#define __PTRDIFF_WIDTH__ 64\n#define __INT_FAST16_WIDTH__ 16\n#define __FLT64_HAS_INFINITY__ 1\n#define __FLT64X_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __FLT16_HAS_INFINITY__ 1\n#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)\n#define __FLT16_MANT_DIG__ 11\n#define __INTPTR_TYPE__ long int\n#define __UINT16_TYPE__ short unsigned int\n#define __WCHAR_TYPE__ int\n#define __pic__ 2\n#define __UINTPTR_MAX__ 0xffffffffffffffffUL\n#define __ARM_ARCH_8A 1\n#define __LDBL_HAS_INFINITY__ 1\n#define __ARM_FEATURE_UNALIGNED 1\n#define __FLT32_DECIMAL_DIG__ 9\n#define __INT_FAST64_MAX__ 0x7fffffffffffffffLL\n#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __FLT64X_MAX_EXP__ 16384\n#define __UINT_FAST64_TYPE__ long long unsigned int\n#define __DEC64X_MANT_DIG__ 34\n#define __BFLT16_MIN_EXP__ (-125)\n#define __INT_MAX__ 0x7fffffff\n#define __INT64_TYPE__ long long int\n#define __FLT_MAX_EXP__ 128\n#define __ORDER_BIG_ENDIAN__ 4321\n#define __DBL_MANT_DIG__ 53\n#define __BFLT16_MANT_DIG__ 8\n#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2\n#define __FP_FAST_FMAF32 1\n#define __WINT_TYPE__ int\n#define __UINT_LEAST32_TYPE__ unsigned int\n#define __SIZEOF_SHORT__ 2\n#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __LDBL_MIN_EXP__ (-1021)\n#define __GCC_ATOMIC_BOOL_LOCK_FREE 2\n#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __DEC64X_MIN_EXP__ (-6142)\n#define __LITTLE_ENDIAN__ 1\n#define __WINT_WIDTH__ 32\n#define __FP_FAST_FMAF64 1\n#define __INT_LEAST8_MAX__ 0x7f\n#define __FLT32X_MAX_10_EXP__ 308\n#define __SIZEOF_INT128__ 16\n#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16\n#define __LDBL_MAX_10_EXP__ 308\n#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)\n#define __INT_LEAST32_TYPE__ int\n#define __FLT32_MIN_EXP__ (-125)\n#define _LP64 1\n#define __UINT8_C(c) c\n#define __FLT64_MAX_EXP__ 1024\n#define __SIZEOF_WCHAR_T__ 4\n#define __UINT64_TYPE__ long long unsigned int\n#define __ARM_FEATURE_CRC32 1\n#define __ARM_NEON 1\n#define __MACH__ 1\n#define __FLT128_HAS_QUIET_NAN__ 1\n#define __INTMAX_MAX__ 0x7fffffffffffffffL\n#define __UINT_FAST8_TYPE__ unsigned char\n#define __INT_FAST8_TYPE__ signed char\n#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x\n#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64\n#define __arm_preserves(...) [[__extension__ arm::preserves(__VA_ARGS__)]]\n#define __GNUC_STDC_INLINE__ 1\n#define __FLT64_HAS_DENORM__ 1\n#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32\n#define __FLT16_HAS_DENORM__ 1\n#define __STDC_UTF_32__ 1\n#define __INT_FAST8_WIDTH__ 8\n#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __ARM_ALIGN_MAX_STACK_PWR 16\n#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221372e-324L\n#define __GCC_DESTRUCTIVE_SIZE 256\n#define __ARM_FEATURE_PAUTH 1\n#define __FLT32_DIG__ 6\n#define __UINT32_C(c) c ## U\n#define __WINT_MIN__ (-__WINT_MAX__ - 1)\n#define __FLT128_IS_IEC_60559__ 1\n#define __INT8_MAX__ 0x7f\n#define __LONG_WIDTH__ 64\n#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)\n#define __PIC__ 2\n#define __INT32_MAX__ 0x7fffffff\n#define __BFLT16_MAX_10_EXP__ 38\n#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __CHAR32_TYPE__ unsigned int\n#define __ARM_FEATURE_NUMERIC_MAXMIN 1\n#define __INT32_TYPE__ int\n#define __SIZEOF_DOUBLE__ 8\n#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64\n#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F\n#define __INT_LEAST32_WIDTH__ 32\n#define __SIZEOF_FLOAT__ 4\n#define __ARM_FEATURE_COMPLEX 1\n#define __builtin_fabsq __builtin_fabsf128\n#define __ATOMIC_CONSUME 1\n#define __SIZE_MAX__ 0xffffffffffffffffUL\n#define __GNUC_MINOR__ 2\n#define __UINTMAX_MAX__ 0xffffffffffffffffUL\n#define __DEC32_MANT_DIG__ 7\n#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x\n#define __arm_locally_streaming [[__extension__ arm::locally_streaming]]\n#define __DBL_MAX_10_EXP__ 308\n#define __INT16_C(c) c\n#define __ARM_ARCH_ISA_A64 1\n#define __ATOMIC_RELEASE 3\n#define __STDC__ 1\n#define __PTRDIFF_TYPE__ long int\n#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1\n#define __UINT32_TYPE__ unsigned int\n#define __FLT32X_MIN_10_EXP__ (-307)\n#define __UINTPTR_TYPE__ long unsigned int\n#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD\n#define __DEC128_MANT_DIG__ 34\n#define __LDBL_MIN_10_EXP__ (-307)\n#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128\n#define __SIZEOF_LONG_LONG__ 8\n#define __FP_FAST_FMAF32x 1\n#define __FLT128_DECIMAL_DIG__ 36\n#define __GCC_ATOMIC_LLONG_LOCK_FREE 2\n#define __FLT_DECIMAL_DIG__ 9\n#define __UINT_FAST16_MAX__ 0xffff\n#define __LDBL_NORM_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT_MIN_10_EXP__ (-37)\n#define __GCC_ATOMIC_SHORT_LOCK_FREE 2\n#define __ORDER_LITTLE_ENDIAN__ 1234\n#define __WCHAR_MAX__ 0x7fffffff\n#define __UINT_LEAST32_MAX__ 0xffffffffU\n#define __ATOMIC_ACQ_REL 4\n", + "flags": "-O2", + "compiler": "gcc-16 (Homebrew GCC 16.2.0) 16.2.0", + "target": "aarch64-apple-darwin24", + "about": "One flag, and the table is not one longer" + }, + "c23": { + "text": "#define __builtin_nanq __builtin_nanf128\n#define __DBL_MIN_EXP__ (-1021)\n#define __UINT_LEAST16_MAX__ 0xffff\n#define __ARM_SIZEOF_WCHAR_T 4\n#define __ATOMIC_ACQUIRE 2\n#define __FLT128_MAX_10_EXP__ 4932\n#define __ARM_STATE_ZT0 1\n#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n#define __GCC_IEC_559_COMPLEX 2\n#define __UINT_LEAST8_TYPE__ unsigned char\n#define __INTMAX_C(c) c ## L\n#define __CHAR_BIT__ 8\n#define __UINT8_MAX__ 0xff\n#define __USER_LABEL_PREFIX__ _\n#define __WINT_MAX__ 0x7fffffff\n#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_MIN_10_EXP__ (-37)\n#define __arm_streaming_compatible [[__extension__ arm::streaming_compatible]]\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1\n#define __GCC_ATOMIC_CHAR_LOCK_FREE 2\n#define __ARM_FEATURE_ATOMICS 1\n#define __GCC_IEC_559 2\n#define __FLT32X_DECIMAL_DIG__ 17\n#define __builtin_nansq __builtin_nansf128\n#define __FLT_EVAL_METHOD__ 0\n#define __FLT64_DECIMAL_DIG__ 17\n#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2\n#define __INTPTR_WIDTH__ 64\n#define __UINT_FAST32_TYPE__ unsigned int\n#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL\n#define __SIG_ATOMIC_TYPE__ int\n#define __ARM_FEATURE_RCPC 1\n#define __DBL_MIN_10_EXP__ (-307)\n#define __FINITE_MATH_ONLY__ 0\n#define __PTRDIFF_MAX__ 0x7fffffffffffffffL\n#define __FLT32X_MAX_EXP__ 1024\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1\n#define __GNUC_PATCHLEVEL__ 0\n#define __FLT32_HAS_DENORM__ 1\n#define __UINT_FAST8_MAX__ 0xff\n#define __FLT32_MAX_10_EXP__ 38\n#define __DEC64_MAX_EXP__ 385\n#define __INT8_C(c) c\n#define __ARM_64BIT_STATE 1\n#define __INT_LEAST8_WIDTH__ 8\n#define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL\n#define __SHRT_MAX__ 0x7fff\n#define __ARM_FEATURE_IDIV 1\n#define __FLT64X_MAX_10_EXP__ 4932\n#define __BFLT16_MAX_EXP__ 128\n#define __ARM_NEON_SVE_BRIDGE 1\n#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __LDBL_IS_IEC_60559__ 1\n#define __ARM_FP 14\n#define __FLT64X_IS_IEC_60559__ 1\n#define __FLT64X_HAS_QUIET_NAN__ 1\n#define __UINT_LEAST8_MAX__ 0xff\n#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128\n#define __APPLE_CC__ 1\n#define __UINTMAX_TYPE__ long unsigned int\n#define __BFLT16_DECIMAL_DIG__ 4\n#define __DEC32_EPSILON__ 1E-6DF\n#define __FLT_EVAL_METHOD_TS_18661_3__ 0\n#define __UINT32_MAX__ 0xffffffffU\n#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)\n#define __AARCH64_CMODEL_SMALL__ 1\n#define __LDBL_MAX_EXP__ 1024\n#define __STDC_EMBED_NOT_FOUND__ 0\n#define __INT_FAST32_WIDTH__ 32\n#define __FLT128_MIN_EXP__ (-16381)\n#define __DEC64X_MAX_EXP__ 6145\n#define __FLT128_MIN_10_EXP__ (-4931)\n#define __FLT32X_IS_IEC_60559__ 1\n#define __INT_LEAST16_WIDTH__ 16\n#define __SCHAR_MAX__ 0x7f\n#define __FLT128_MANT_DIG__ 113\n#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)\n#define __INT64_C(c) c ## LL\n#define __GCC_ATOMIC_POINTER_LOCK_FREE 2\n#define __ATOMIC_SEQ_CST 5\n#define __SIZEOF_INT__ 4\n#define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL\n#define __ARM_FEATURE_CLZ 1\n#define __ARM_STATE_ZA 1\n#define __FLT32X_MANT_DIG__ 53\n#define __LDBL_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT64X_EPSILON__ 1.92592994438723585305597794258492732e-34F64x\n#define __STDC_HOSTED__ 1\n#define __DEC64_MIN_EXP__ (-382)\n#define __DBL_DIG__ 15\n#define __STDC_EMBED_EMPTY__ 2\n#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n#define __SHRT_WIDTH__ 16\n#define __DEC64_MIN__ 1E-383DD\n#define __FLT32_IS_IEC_60559__ 1\n#define __LDBL_MIN__ 2.22507385850720138309023271733240406e-308L\n#define __STDC_UTF_16__ 1\n#define __DBL_IS_IEC_60559__ 1\n#define __DEC32_MAX__ 9.999999E96DF\n#define __FLT16_HAS_QUIET_NAN__ 1\n#define __CHAR8_TYPE__ unsigned char\n#define __strong \n#define __ARM_SIZEOF_MINIMAL_ENUM 4\n#define __FLT64X_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F64x\n#define __FP_FAST_FMA 1\n#define __FLT32X_HAS_INFINITY__ 1\n#define __FLT16_DIG__ 3\n#define __INT_WIDTH__ 32\n#define __BFLT16_DIG__ 2\n#define __SIZE_WIDTH__ 64\n#define __ARM_FEATURE_JCVT 1\n#define __APPLE__ 1\n#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2\n#define __DECIMAL_DIG__ 17\n#define __ARM_FEATURE_DOTPROD 1\n#define __INT16_MAX__ 0x7fff\n#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL\n#define __FLT64X_MIN_10_EXP__ (-4931)\n#define __LDBL_HAS_QUIET_NAN__ 1\n#define __FLT16_MIN_EXP__ (-13)\n#define __FLT64_MANT_DIG__ 53\n#define __LDBL_MANT_DIG__ 53\n#define __FLT64X_MANT_DIG__ 113\n#define __DYNAMIC__ 1\n#define __GNUC__ 16\n#define __FLT16_DECIMAL_DIG__ 5\n#define __FLT_HAS_DENORM__ 1\n#define __SIZEOF_LONG_DOUBLE__ 8\n#define __arm_new(...) [[__extension__ arm::new(__VA_ARGS__)]]\n#define __LDBL_DIG__ 15\n#define __SIZE_TYPE__ long unsigned int\n#define __FLT64_MAX_10_EXP__ 308\n#define __INTMAX_TYPE__ long int\n#define __FLT16_MAX_10_EXP__ 4\n#define __INT_FAST32_MAX__ 0x7fffffff\n#define __DBL_HAS_INFINITY__ 1\n#define __HAVE_SPECULATION_SAFE_VALUE 1\n#define __DEC32_MIN_EXP__ (-94)\n#define __builtin_huge_valq __builtin_huge_valf128\n#define __FLT32X_HAS_DENORM__ 1\n#define __INT_FAST16_TYPE__ short int\n#define __STRICT_ANSI__ 1\n#define __LDBL_HAS_DENORM__ 1\n#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16\n#define __FLT128_HAS_INFINITY__ 1\n#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL\n#define __DEC32_MIN__ 1E-95DF\n#define __weak \n#define __ARM_FEATURE_FRINT 1\n#define __DBL_MAX_EXP__ 1024\n#define __WCHAR_WIDTH__ 32\n#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __DEC128_EPSILON__ 1E-33DL\n#define __GCC_ATOMIC_LONG_LOCK_FREE 2\n#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16\n#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x\n#define __FLT32_HAS_QUIET_NAN__ 1\n#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL\n#define __SIZEOF_SIZE_T__ 8\n#define __CONSTANT_CFSTRINGS__ 1\n#define __SIG_ATOMIC_WIDTH__ 32\n#define __FLT64X_HAS_INFINITY__ 1\n#define __ARM_ALIGN_MAX_PWR 28\n#define __BFLT16_HAS_INFINITY__ 1\n#define __SIZEOF_WINT_T__ 4\n#define __LDBL_DECIMAL_DIG__ 17\n#define __LONG_LONG_WIDTH__ 64\n#define __FLT32_MAX_EXP__ 128\n#define __ARM_FP16_FORMAT_IEEE 1\n#define __builtin_infq __builtin_inff128\n#define __FLT_MIN_EXP__ (-125)\n#define __FLT32X_MIN_EXP__ (-1021)\n#define __INT_FAST64_TYPE__ long long int\n#define __ARM_FP16_ARGS 1\n#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __DBL_DECIMAL_DIG__ 17\n#define __FP_FAST_FMAF 1\n#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __FP_FAST_FMAL 1\n#define __BFLT16_HAS_DENORM__ 1\n#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64\n#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16\n#define __FLT64X_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __SIZEOF_POINTER__ 8\n#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128\n#define __LP64__ 1\n#define __DBL_HAS_QUIET_NAN__ 1\n#define __FLT_EVAL_METHOD_C99__ 0\n#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x\n#define __DECIMAL_BID_FORMAT__ 1\n#define __FLT64_MIN_EXP__ (-1021)\n#define __arm_in(...) [[__extension__ arm::in(__VA_ARGS__)]]\n#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __aarch64__ 1\n#define __FLT64_MIN_10_EXP__ (-307)\n#define __INT_FAST64_WIDTH__ 64\n#define __FLT64X_DECIMAL_DIG__ 36\n#define __DEC128_MIN__ 1E-6143DL\n#define __REGISTER_PREFIX__ \n#define __UINT16_MAX__ 0xffff\n#define __INTMAX_WIDTH__ 64\n#define __GXX_ABI_VERSION 1021\n#define __AARCH64EL__ 1\n#define __UINT8_TYPE__ unsigned char\n#define __FLT_DIG__ 6\n#define __NO_INLINE__ 1\n#define __arm_out(...) [[__extension__ arm::out(__VA_ARGS__)]]\n#define __DEC_EVAL_METHOD__ 2\n#define __FLT_MANT_DIG__ 24\n#define __FLT16_MIN_10_EXP__ (-4)\n#define __VERSION__ \"16.2.0\"\n#define __UINT64_C(c) c ## ULL\n#define __ARM_FEATURE_QRDMX 1\n#define __DEC64X_MIN__ 1E-6143D64x\n#define __INT_LEAST32_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_INT_LOCK_FREE 2\n#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x\n#define __FLT128_MAX_EXP__ 16384\n#define __FLT32_MANT_DIG__ 24\n#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __DEC128_MAX_EXP__ 6145\n#define __FLT16_MAX_EXP__ 16\n#define __BIGGEST_ALIGNMENT__ 16\n#define __INT32_C(c) c\n#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16\n#define __FLT128_HAS_DENORM__ 1\n#define __FLT128_DIG__ 33\n#define __SCHAR_WIDTH__ 8\n#define __DEC64_EPSILON__ 1E-15DD\n#define __ORDER_PDP_ENDIAN__ 3412\n#define __DEC128_MIN_EXP__ (-6142)\n#define __INT_FAST32_TYPE__ int\n#define __UINT_LEAST16_TYPE__ short unsigned int\n#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 150000\n#define __UINT64_MAX__ 0xffffffffffffffffULL\n#define __FLT_IS_IEC_60559__ 1\n#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"\n#define __FLT64X_DIG__ 33\n#define __ARM_FEATURE_FMA 1\n#define __INT8_TYPE__ signed char\n#define __GCC_ASM_FLAG_OUTPUTS__ 1\n#define __arm64__ 1\n#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1\n#define __BFLT16_HAS_QUIET_NAN__ 1\n#define __FLT_RADIX__ 2\n#define __INT_LEAST16_TYPE__ short int\n#define __ARM_ARCH_PROFILE 65\n#define __LDBL_EPSILON__ 2.22044604925031308084726333618164062e-16L\n#define __UINTMAX_C(c) c ## UL\n#define __DEC64X_EPSILON__ 1E-33D64x\n#define __ARM_PCS_AAPCS64 1\n#define __builtin_copysignq __builtin_copysignf128\n#define __SIG_ATOMIC_MAX__ 0x7fffffff\n#define __INT64_MAX__ 0x7fffffffffffffffLL\n#define __INT_LEAST64_WIDTH__ 64\n#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2\n#define __SIZEOF_PTRDIFF_T__ 8\n#define __arm64 1\n#define __ATOMIC_RELAXED 0\n#define __BFLT16_IS_IEC_60559__ 0\n#define __SIZEOF_LONG__ 8\n#define __FLT64_IS_IEC_60559__ 1\n#define __FLT16_IS_IEC_60559__ 1\n#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF\n#define __STDC_EMBED_FOUND__ 1\n#define __INT_FAST16_MAX__ 0x7fff\n#define __GCC_CONSTRUCTIVE_SIZE 64\n#define __FLT64_DIG__ 15\n#define __UINT_FAST32_MAX__ 0xffffffffU\n#define __UINT_LEAST64_TYPE__ long long unsigned int\n#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16\n#define __FLT_HAS_QUIET_NAN__ 1\n#define __FLT_MAX_10_EXP__ 38\n#define __LONG_MAX__ 0x7fffffffffffffffL\n#define __FLT64X_HAS_DENORM__ 1\n#define __FLT_HAS_INFINITY__ 1\n#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"\n#define __DBL_HAS_DENORM__ 1\n#define __UINT_FAST16_TYPE__ short unsigned int\n#define __DEC64_MAX__ 9.999999999999999E384DD\n#define __FLT32X_HAS_QUIET_NAN__ 1\n#define __CHAR16_TYPE__ short unsigned int\n#define __PRAGMA_REDEFINE_EXTNAME 1\n#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x\n#define __BITINT_MAXWIDTH__ 65535\n#define __INT_LEAST16_MAX__ 0x7fff\n#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __DEC64_MANT_DIG__ 16\n#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32\n#define __INT_LEAST64_TYPE__ long long int\n#define __INT16_TYPE__ short int\n#define __INT_LEAST8_TYPE__ signed char\n#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __STDC_VERSION__ 202311L\n#define __DEC32_MAX_EXP__ 97\n#define __INT_FAST8_MAX__ 0x7f\n#define __ARM_ARCH 8\n#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __INTPTR_MAX__ 0x7fffffffffffffffL\n#define __arm_inout(...) [[__extension__ arm::inout(__VA_ARGS__)]]\n#define __arm_streaming [[__extension__ arm::streaming]]\n#define __FLT64_HAS_QUIET_NAN__ 1\n#define __ARM_FEATURE_BTI 1\n#define __FLT64X_MIN_EXP__ (-16381)\n#define __FLT32_MIN_10_EXP__ (-37)\n#define __FLT32X_DIG__ 15\n#define __UINT16_C(c) c\n#define __PTRDIFF_WIDTH__ 64\n#define __INT_FAST16_WIDTH__ 16\n#define __FLT64_HAS_INFINITY__ 1\n#define __FLT64X_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __FLT16_HAS_INFINITY__ 1\n#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)\n#define __FLT16_MANT_DIG__ 11\n#define __INTPTR_TYPE__ long int\n#define __UINT16_TYPE__ short unsigned int\n#define __WCHAR_TYPE__ int\n#define __pic__ 2\n#define __UINTPTR_MAX__ 0xffffffffffffffffUL\n#define __ARM_ARCH_8A 1\n#define __LDBL_HAS_INFINITY__ 1\n#define __ARM_FEATURE_UNALIGNED 1\n#define __FLT32_DECIMAL_DIG__ 9\n#define __INT_FAST64_MAX__ 0x7fffffffffffffffLL\n#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __FLT32_HAS_INFINITY__ 1\n#define __FLT64X_MAX_EXP__ 16384\n#define __UINT_FAST64_TYPE__ long long unsigned int\n#define __DEC64X_MANT_DIG__ 34\n#define __BFLT16_MIN_EXP__ (-125)\n#define __INT_MAX__ 0x7fffffff\n#define __INT64_TYPE__ long long int\n#define __FLT_MAX_EXP__ 128\n#define __ORDER_BIG_ENDIAN__ 4321\n#define __DBL_MANT_DIG__ 53\n#define __BFLT16_MANT_DIG__ 8\n#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2\n#define __FP_FAST_FMAF32 1\n#define __WINT_TYPE__ int\n#define __UINT_LEAST32_TYPE__ unsigned int\n#define __SIZEOF_SHORT__ 2\n#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __LDBL_MIN_EXP__ (-1021)\n#define __GCC_ATOMIC_BOOL_LOCK_FREE 2\n#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __DEC64X_MIN_EXP__ (-6142)\n#define __LITTLE_ENDIAN__ 1\n#define __WINT_WIDTH__ 32\n#define __FP_FAST_FMAF64 1\n#define __INT_LEAST8_MAX__ 0x7f\n#define __FLT32X_MAX_10_EXP__ 308\n#define __SIZEOF_INT128__ 16\n#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16\n#define __LDBL_MAX_10_EXP__ 308\n#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)\n#define __INT_LEAST32_TYPE__ int\n#define __FLT32_MIN_EXP__ (-125)\n#define _LP64 1\n#define __UINT8_C(c) c\n#define __FLT64_MAX_EXP__ 1024\n#define __SIZEOF_WCHAR_T__ 4\n#define __UINT64_TYPE__ long long unsigned int\n#define __ARM_FEATURE_CRC32 1\n#define __ARM_NEON 1\n#define __MACH__ 1\n#define __FLT128_HAS_QUIET_NAN__ 1\n#define __INTMAX_MAX__ 0x7fffffffffffffffL\n#define __UINT_FAST8_TYPE__ unsigned char\n#define __INT_FAST8_TYPE__ signed char\n#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x\n#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64\n#define __arm_preserves(...) [[__extension__ arm::preserves(__VA_ARGS__)]]\n#define __GNUC_STDC_INLINE__ 1\n#define __FLT64_HAS_DENORM__ 1\n#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32\n#define __FLT16_HAS_DENORM__ 1\n#define __STDC_UTF_32__ 1\n#define __INT_FAST8_WIDTH__ 8\n#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __ARM_ALIGN_MAX_STACK_PWR 16\n#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221372e-324L\n#define __GCC_DESTRUCTIVE_SIZE 256\n#define __ARM_FEATURE_PAUTH 1\n#define __FLT32_DIG__ 6\n#define __UINT32_C(c) c ## U\n#define __WINT_MIN__ (-__WINT_MAX__ - 1)\n#define __FLT128_IS_IEC_60559__ 1\n#define __INT8_MAX__ 0x7f\n#define __LONG_WIDTH__ 64\n#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)\n#define __PIC__ 2\n#define __INT32_MAX__ 0x7fffffff\n#define __BFLT16_MAX_10_EXP__ 38\n#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __CHAR32_TYPE__ unsigned int\n#define __ARM_FEATURE_NUMERIC_MAXMIN 1\n#define __INT32_TYPE__ int\n#define __SIZEOF_DOUBLE__ 8\n#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64\n#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F\n#define __INT_LEAST32_WIDTH__ 32\n#define __SIZEOF_FLOAT__ 4\n#define __ARM_FEATURE_COMPLEX 1\n#define __builtin_fabsq __builtin_fabsf128\n#define __ATOMIC_CONSUME 1\n#define __SIZE_MAX__ 0xffffffffffffffffUL\n#define __GNUC_MINOR__ 2\n#define __UINTMAX_MAX__ 0xffffffffffffffffUL\n#define __DEC32_MANT_DIG__ 7\n#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x\n#define __arm_locally_streaming [[__extension__ arm::locally_streaming]]\n#define __DBL_MAX_10_EXP__ 308\n#define __INT16_C(c) c\n#define __ARM_ARCH_ISA_A64 1\n#define __ATOMIC_RELEASE 3\n#define __STDC__ 1\n#define __PTRDIFF_TYPE__ long int\n#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1\n#define __UINT32_TYPE__ unsigned int\n#define __FLT32X_MIN_10_EXP__ (-307)\n#define __UINTPTR_TYPE__ long unsigned int\n#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD\n#define __DEC128_MANT_DIG__ 34\n#define __LDBL_MIN_10_EXP__ (-307)\n#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128\n#define __SIZEOF_LONG_LONG__ 8\n#define __FP_FAST_FMAF32x 1\n#define __FLT128_DECIMAL_DIG__ 36\n#define __GCC_ATOMIC_LLONG_LOCK_FREE 2\n#define __FLT_DECIMAL_DIG__ 9\n#define __UINT_FAST16_MAX__ 0xffff\n#define __LDBL_NORM_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT_MIN_10_EXP__ (-37)\n#define __GCC_ATOMIC_SHORT_LOCK_FREE 2\n#define __ORDER_LITTLE_ENDIAN__ 1234\n#define __WCHAR_MAX__ 0x7fffffff\n#define __UINT_LEAST32_MAX__ 0xffffffffU\n#define __ATOMIC_ACQ_REL 4\n", + "flags": "-std=c23", + "compiler": "gcc-16 (Homebrew GCC 16.2.0) 16.2.0", + "target": "aarch64-apple-darwin24", + "about": "The flag that names a language standard, and does not change it" + }, + "fast": { + "text": "#define __builtin_nanq __builtin_nanf128\n#define __DBL_MIN_EXP__ (-1021)\n#define __UINT_LEAST16_MAX__ 0xffff\n#define __ARM_SIZEOF_WCHAR_T 4\n#define __ATOMIC_ACQUIRE 2\n#define __FLT128_MAX_10_EXP__ 4932\n#define __ARM_STATE_ZT0 1\n#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n#define __GCC_IEC_559_COMPLEX 0\n#define __UINT_LEAST8_TYPE__ unsigned char\n#define __INTMAX_C(c) c ## L\n#define __CHAR_BIT__ 8\n#define __UINT8_MAX__ 0xff\n#define __USER_LABEL_PREFIX__ _\n#define __WINT_MAX__ 0x7fffffff\n#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __BFLT16_MIN_10_EXP__ (-37)\n#define __arm_streaming_compatible [[__extension__ arm::streaming_compatible]]\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1\n#define __GCC_ATOMIC_CHAR_LOCK_FREE 2\n#define __ARM_FEATURE_ATOMICS 1\n#define __GCC_IEC_559 0\n#define __FLT32X_DECIMAL_DIG__ 17\n#define __builtin_nansq __builtin_nansf128\n#define __FLT_EVAL_METHOD__ 0\n#define __FLT64_DECIMAL_DIG__ 17\n#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2\n#define __INTPTR_WIDTH__ 64\n#define __UINT_FAST32_TYPE__ unsigned int\n#define __UINT_FAST64_MAX__ 0xffffffffffffffffULL\n#define __SIG_ATOMIC_TYPE__ int\n#define __ARM_FEATURE_RCPC 1\n#define __DBL_MIN_10_EXP__ (-307)\n#define __FINITE_MATH_ONLY__ 1\n#define __PTRDIFF_MAX__ 0x7fffffffffffffffL\n#define __FLT32X_MAX_EXP__ 1024\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1\n#define __GNUC_PATCHLEVEL__ 0\n#define __FLT32_HAS_DENORM__ 1\n#define __UINT_FAST8_MAX__ 0xff\n#define __FLT32_MAX_10_EXP__ 38\n#define __DEC64_MAX_EXP__ 385\n#define __INT8_C(c) c\n#define __ARM_64BIT_STATE 1\n#define __INT_LEAST8_WIDTH__ 8\n#define __UINT_LEAST64_MAX__ 0xffffffffffffffffULL\n#define __SHRT_MAX__ 0x7fff\n#define __ARM_FEATURE_IDIV 1\n#define __FLT64X_MAX_10_EXP__ 4932\n#define __BFLT16_MAX_EXP__ 128\n#define __ARM_NEON_SVE_BRIDGE 1\n#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __LDBL_IS_IEC_60559__ 1\n#define __ARM_FP 14\n#define __FLT64X_IS_IEC_60559__ 1\n#define __FLT64X_HAS_QUIET_NAN__ 1\n#define __UINT_LEAST8_MAX__ 0xff\n#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128\n#define __APPLE_CC__ 1\n#define __UINTMAX_TYPE__ long unsigned int\n#define __BFLT16_DECIMAL_DIG__ 4\n#define __DEC32_EPSILON__ 1E-6DF\n#define __FLT_EVAL_METHOD_TS_18661_3__ 0\n#define __UINT32_MAX__ 0xffffffffU\n#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)\n#define __AARCH64_CMODEL_SMALL__ 1\n#define __LDBL_MAX_EXP__ 1024\n#define __STDC_EMBED_NOT_FOUND__ 0\n#define __INT_FAST32_WIDTH__ 32\n#define __FLT128_MIN_EXP__ (-16381)\n#define __DEC64X_MAX_EXP__ 6145\n#define __FLT128_MIN_10_EXP__ (-4931)\n#define __FLT32X_IS_IEC_60559__ 1\n#define __INT_LEAST16_WIDTH__ 16\n#define __SCHAR_MAX__ 0x7f\n#define __FLT128_MANT_DIG__ 113\n#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)\n#define __INT64_C(c) c ## LL\n#define __GCC_ATOMIC_POINTER_LOCK_FREE 2\n#define __ATOMIC_SEQ_CST 5\n#define __SIZEOF_INT__ 4\n#define __INT_LEAST64_MAX__ 0x7fffffffffffffffLL\n#define __ARM_FEATURE_CLZ 1\n#define __ARM_STATE_ZA 1\n#define __FLT32X_MANT_DIG__ 53\n#define __LDBL_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT64X_EPSILON__ 1.92592994438723585305597794258492732e-34F64x\n#define __STDC_HOSTED__ 1\n#define __NO_MATH_ERRNO__ 1\n#define __DEC64_MIN_EXP__ (-382)\n#define __DBL_DIG__ 15\n#define __ASSOCIATIVE_MATH__ 1\n#define __STDC_EMBED_EMPTY__ 2\n#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n#define __SHRT_WIDTH__ 16\n#define __DEC64_MIN__ 1E-383DD\n#define __FLT32_IS_IEC_60559__ 1\n#define __LDBL_MIN__ 2.22507385850720138309023271733240406e-308L\n#define __STDC_UTF_16__ 1\n#define __DBL_IS_IEC_60559__ 1\n#define __DEC32_MAX__ 9.999999E96DF\n#define __FLT16_HAS_QUIET_NAN__ 1\n#define __CHAR8_TYPE__ unsigned char\n#define __strong \n#define __ARM_SIZEOF_MINIMAL_ENUM 4\n#define __FLT64X_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F64x\n#define __FP_FAST_FMA 1\n#define __FLT32X_HAS_INFINITY__ 1\n#define __FLT16_DIG__ 3\n#define __INT_WIDTH__ 32\n#define __BFLT16_DIG__ 2\n#define __SIZE_WIDTH__ 64\n#define __ARM_FEATURE_JCVT 1\n#define __APPLE__ 1\n#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2\n#define __DECIMAL_DIG__ 17\n#define __ARM_FEATURE_DOTPROD 1\n#define __INT16_MAX__ 0x7fff\n#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL\n#define __FLT64X_MIN_10_EXP__ (-4931)\n#define __LDBL_HAS_QUIET_NAN__ 1\n#define __FLT16_MIN_EXP__ (-13)\n#define __FLT64_MANT_DIG__ 53\n#define __LDBL_MANT_DIG__ 53\n#define __FLT64X_MANT_DIG__ 113\n#define __DYNAMIC__ 1\n#define __GNUC__ 16\n#define __FLT16_DECIMAL_DIG__ 5\n#define __FLT_HAS_DENORM__ 1\n#define __SIZEOF_LONG_DOUBLE__ 8\n#define __arm_new(...) [[__extension__ arm::new(__VA_ARGS__)]]\n#define __LDBL_DIG__ 15\n#define __SIZE_TYPE__ long unsigned int\n#define __FLT64_MAX_10_EXP__ 308\n#define __INTMAX_TYPE__ long int\n#define __FLT16_MAX_10_EXP__ 4\n#define __INT_FAST32_MAX__ 0x7fffffff\n#define __DBL_HAS_INFINITY__ 1\n#define __HAVE_SPECULATION_SAFE_VALUE 1\n#define __DEC32_MIN_EXP__ (-94)\n#define __builtin_huge_valq __builtin_huge_valf128\n#define __FLT32X_HAS_DENORM__ 1\n#define __INT_FAST16_TYPE__ short int\n#define __LDBL_HAS_DENORM__ 1\n#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16\n#define __FLT128_HAS_INFINITY__ 1\n#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL\n#define __DEC32_MIN__ 1E-95DF\n#define __weak \n#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32\n#define __ARM_FEATURE_FRINT 1\n#define __DBL_MAX_EXP__ 1024\n#define __WCHAR_WIDTH__ 32\n#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __DEC128_EPSILON__ 1E-33DL\n#define __GCC_ATOMIC_LONG_LOCK_FREE 2\n#define __FAST_MATH__ 1\n#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16\n#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x\n#define __FLT32_HAS_QUIET_NAN__ 1\n#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL\n#define __SIZEOF_SIZE_T__ 8\n#define __CONSTANT_CFSTRINGS__ 1\n#define __SIG_ATOMIC_WIDTH__ 32\n#define __FLT64X_HAS_INFINITY__ 1\n#define __ARM_ALIGN_MAX_PWR 28\n#define __BFLT16_HAS_INFINITY__ 1\n#define __SIZEOF_WINT_T__ 4\n#define __LDBL_DECIMAL_DIG__ 17\n#define __LONG_LONG_WIDTH__ 64\n#define __FLT32_MAX_EXP__ 128\n#define __ARM_FP16_FORMAT_IEEE 1\n#define __builtin_infq __builtin_inff128\n#define __FLT_MIN_EXP__ (-125)\n#define __FLT32X_MIN_EXP__ (-1021)\n#define __INT_FAST64_TYPE__ long long int\n#define __ARM_FP16_ARGS 1\n#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16\n#define __DBL_DECIMAL_DIG__ 17\n#define __FP_FAST_FMAF 1\n#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __FP_FAST_FMAL 1\n#define __BFLT16_HAS_DENORM__ 1\n#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64\n#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16\n#define __FLT64X_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __SIZEOF_POINTER__ 8\n#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128\n#define __NO_SIGNED_ZEROS__ 1\n#define __LP64__ 1\n#define __DBL_HAS_QUIET_NAN__ 1\n#define __FLT_EVAL_METHOD_C99__ 0\n#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x\n#define __DECIMAL_BID_FORMAT__ 1\n#define __FLT64_MIN_EXP__ (-1021)\n#define __arm_in(...) [[__extension__ arm::in(__VA_ARGS__)]]\n#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __aarch64__ 1\n#define __FLT64_MIN_10_EXP__ (-307)\n#define __INT_FAST64_WIDTH__ 64\n#define __FLT64X_DECIMAL_DIG__ 36\n#define __DEC128_MIN__ 1E-6143DL\n#define __REGISTER_PREFIX__ \n#define __UINT16_MAX__ 0xffff\n#define __INTMAX_WIDTH__ 64\n#define __GXX_ABI_VERSION 1021\n#define __AARCH64EL__ 1\n#define __UINT8_TYPE__ unsigned char\n#define __FLT_DIG__ 6\n#define __NO_INLINE__ 1\n#define __arm_out(...) [[__extension__ arm::out(__VA_ARGS__)]]\n#define __DEC_EVAL_METHOD__ 2\n#define __FLT_MANT_DIG__ 24\n#define __FLT16_MIN_10_EXP__ (-4)\n#define __VERSION__ \"16.2.0\"\n#define __UINT64_C(c) c ## ULL\n#define __ARM_FEATURE_QRDMX 1\n#define __DEC64X_MIN__ 1E-6143D64x\n#define __INT_LEAST32_MAX__ 0x7fffffff\n#define __GCC_ATOMIC_INT_LOCK_FREE 2\n#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x\n#define __FLT128_MAX_EXP__ 16384\n#define __FLT32_MANT_DIG__ 24\n#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __DEC128_MAX_EXP__ 6145\n#define __FLT16_MAX_EXP__ 16\n#define __BIGGEST_ALIGNMENT__ 16\n#define __INT32_C(c) c\n#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16\n#define __FLT128_HAS_DENORM__ 1\n#define __FLT128_DIG__ 33\n#define __SCHAR_WIDTH__ 8\n#define __DEC64_EPSILON__ 1E-15DD\n#define __ORDER_PDP_ENDIAN__ 3412\n#define __DEC128_MIN_EXP__ (-6142)\n#define __INT_FAST32_TYPE__ int\n#define __UINT_LEAST16_TYPE__ short unsigned int\n#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 150000\n#define __UINT64_MAX__ 0xffffffffffffffffULL\n#define __FLT_IS_IEC_60559__ 1\n#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"\n#define __FLT64X_DIG__ 33\n#define __ARM_FEATURE_FMA 1\n#define __INT8_TYPE__ signed char\n#define __GCC_ASM_FLAG_OUTPUTS__ 1\n#define __arm64__ 1\n#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1\n#define __RECIPROCAL_MATH__ 1\n#define __BFLT16_HAS_QUIET_NAN__ 1\n#define __FLT_RADIX__ 2\n#define __INT_LEAST16_TYPE__ short int\n#define __ARM_ARCH_PROFILE 65\n#define __LDBL_EPSILON__ 2.22044604925031308084726333618164062e-16L\n#define __UINTMAX_C(c) c ## UL\n#define __DEC64X_EPSILON__ 1E-33D64x\n#define __ARM_PCS_AAPCS64 1\n#define __builtin_copysignq __builtin_copysignf128\n#define __SIG_ATOMIC_MAX__ 0x7fffffff\n#define __INT64_MAX__ 0x7fffffffffffffffLL\n#define __INT_LEAST64_WIDTH__ 64\n#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2\n#define __SIZEOF_PTRDIFF_T__ 8\n#define __arm64 1\n#define __ATOMIC_RELAXED 0\n#define __BFLT16_IS_IEC_60559__ 0\n#define __FLT32_HAS_INFINITY__ 1\n#define __SIZEOF_LONG__ 8\n#define __FLT64_IS_IEC_60559__ 1\n#define __FLT16_IS_IEC_60559__ 1\n#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF\n#define __STDC_EMBED_FOUND__ 1\n#define __INT_FAST16_MAX__ 0x7fff\n#define __GCC_CONSTRUCTIVE_SIZE 64\n#define __FLT64_DIG__ 15\n#define __UINT_FAST32_MAX__ 0xffffffffU\n#define __UINT_LEAST64_TYPE__ long long unsigned int\n#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16\n#define __FLT_HAS_QUIET_NAN__ 1\n#define __FLT_MAX_10_EXP__ 38\n#define __LONG_MAX__ 0x7fffffffffffffffL\n#define __FLT64X_HAS_DENORM__ 1\n#define __FLT_HAS_INFINITY__ 1\n#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"\n#define __DBL_HAS_DENORM__ 1\n#define __UINT_FAST16_TYPE__ short unsigned int\n#define __DEC64_MAX__ 9.999999999999999E384DD\n#define __FLT32X_HAS_QUIET_NAN__ 1\n#define __CHAR16_TYPE__ short unsigned int\n#define __PRAGMA_REDEFINE_EXTNAME 1\n#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x\n#define __BITINT_MAXWIDTH__ 65535\n#define __INT_LEAST16_MAX__ 0x7fff\n#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __DEC64_MANT_DIG__ 16\n#define __NO_TRAPPING_MATH__ 1\n#define __INT_LEAST64_TYPE__ long long int\n#define __INT16_TYPE__ short int\n#define __INT_LEAST8_TYPE__ signed char\n#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16\n#define __STDC_VERSION__ 202311L\n#define __DEC32_MAX_EXP__ 97\n#define __INT_FAST8_MAX__ 0x7f\n#define __ARM_ARCH 8\n#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128\n#define __INTPTR_MAX__ 0x7fffffffffffffffL\n#define __arm_inout(...) [[__extension__ arm::inout(__VA_ARGS__)]]\n#define __arm_streaming [[__extension__ arm::streaming]]\n#define __FLT64_HAS_QUIET_NAN__ 1\n#define __ARM_FEATURE_BTI 1\n#define __FLT64X_MIN_EXP__ (-16381)\n#define __FLT32_MIN_10_EXP__ (-37)\n#define __FLT32X_DIG__ 15\n#define __UINT16_C(c) c\n#define __PTRDIFF_WIDTH__ 64\n#define __INT_FAST16_WIDTH__ 16\n#define __FLT64_HAS_INFINITY__ 1\n#define __FLT64X_MAX__ 1.18973149535723176508575932662800702e+4932F64x\n#define __FLT16_HAS_INFINITY__ 1\n#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)\n#define __FLT16_MANT_DIG__ 11\n#define __INTPTR_TYPE__ long int\n#define __UINT16_TYPE__ short unsigned int\n#define __WCHAR_TYPE__ int\n#define __pic__ 2\n#define __UINTPTR_MAX__ 0xffffffffffffffffUL\n#define __ARM_ARCH_8A 1\n#define __LDBL_HAS_INFINITY__ 1\n#define __ARM_FEATURE_UNALIGNED 1\n#define __FLT32_DECIMAL_DIG__ 9\n#define __INT_FAST64_MAX__ 0x7fffffffffffffffLL\n#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F\n#define __FLT64X_MAX_EXP__ 16384\n#define __UINT_FAST64_TYPE__ long long unsigned int\n#define __DEC64X_MANT_DIG__ 34\n#define __BFLT16_MIN_EXP__ (-125)\n#define __INT_MAX__ 0x7fffffff\n#define __INT64_TYPE__ long long int\n#define __FLT_MAX_EXP__ 128\n#define __ORDER_BIG_ENDIAN__ 4321\n#define __DBL_MANT_DIG__ 53\n#define __BFLT16_MANT_DIG__ 8\n#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2\n#define __FP_FAST_FMAF32 1\n#define __WINT_TYPE__ int\n#define __UINT_LEAST32_TYPE__ unsigned int\n#define __SIZEOF_SHORT__ 2\n#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32\n#define __LDBL_MIN_EXP__ (-1021)\n#define __GCC_ATOMIC_BOOL_LOCK_FREE 2\n#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64\n#define __DEC64X_MIN_EXP__ (-6142)\n#define __LITTLE_ENDIAN__ 1\n#define __WINT_WIDTH__ 32\n#define __FP_FAST_FMAF64 1\n#define __INT_LEAST8_MAX__ 0x7f\n#define __FLT32X_MAX_10_EXP__ 308\n#define __SIZEOF_INT128__ 16\n#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16\n#define __LDBL_MAX_10_EXP__ 308\n#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)\n#define __INT_LEAST32_TYPE__ int\n#define __FLT32_MIN_EXP__ (-125)\n#define _LP64 1\n#define __UINT8_C(c) c\n#define __FLT64_MAX_EXP__ 1024\n#define __SIZEOF_WCHAR_T__ 4\n#define __UINT64_TYPE__ long long unsigned int\n#define __ARM_FEATURE_CRC32 1\n#define __ARM_NEON 1\n#define __MACH__ 1\n#define __FLT128_HAS_QUIET_NAN__ 1\n#define __INTMAX_MAX__ 0x7fffffffffffffffL\n#define __UINT_FAST8_TYPE__ unsigned char\n#define __INT_FAST8_TYPE__ signed char\n#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x\n#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64\n#define __arm_preserves(...) [[__extension__ arm::preserves(__VA_ARGS__)]]\n#define __GNUC_STDC_INLINE__ 1\n#define __FLT64_HAS_DENORM__ 1\n#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32\n#define __FLT16_HAS_DENORM__ 1\n#define __STDC_UTF_32__ 1\n#define __INT_FAST8_WIDTH__ 8\n#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)\n#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__\n#define __ARM_ALIGN_MAX_STACK_PWR 16\n#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221372e-324L\n#define __GCC_DESTRUCTIVE_SIZE 256\n#define __ARM_FEATURE_PAUTH 1\n#define __ARM_FP_FAST 1\n#define __FLT32_DIG__ 6\n#define __UINT32_C(c) c ## U\n#define __WINT_MIN__ (-__WINT_MAX__ - 1)\n#define __FLT128_IS_IEC_60559__ 1\n#define __INT8_MAX__ 0x7f\n#define __LONG_WIDTH__ 64\n#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)\n#define __PIC__ 2\n#define __INT32_MAX__ 0x7fffffff\n#define __BFLT16_MAX_10_EXP__ 38\n#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x\n#define __CHAR32_TYPE__ unsigned int\n#define __ARM_FEATURE_NUMERIC_MAXMIN 1\n#define __INT32_TYPE__ int\n#define __SIZEOF_DOUBLE__ 8\n#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64\n#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F\n#define __INT_LEAST32_WIDTH__ 32\n#define __SIZEOF_FLOAT__ 4\n#define __ARM_FEATURE_COMPLEX 1\n#define __builtin_fabsq __builtin_fabsf128\n#define __ATOMIC_CONSUME 1\n#define __SIZE_MAX__ 0xffffffffffffffffUL\n#define __GNUC_MINOR__ 2\n#define __UINTMAX_MAX__ 0xffffffffffffffffUL\n#define __DEC32_MANT_DIG__ 7\n#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x\n#define __arm_locally_streaming [[__extension__ arm::locally_streaming]]\n#define __DBL_MAX_10_EXP__ 308\n#define __INT16_C(c) c\n#define __ARM_ARCH_ISA_A64 1\n#define __ATOMIC_RELEASE 3\n#define __STDC__ 1\n#define __PTRDIFF_TYPE__ long int\n#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32\n#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1\n#define __UINT32_TYPE__ unsigned int\n#define __FLT32X_MIN_10_EXP__ (-307)\n#define __UINTPTR_TYPE__ long unsigned int\n#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD\n#define __DEC128_MANT_DIG__ 34\n#define __LDBL_MIN_10_EXP__ (-307)\n#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128\n#define __SIZEOF_LONG_LONG__ 8\n#define __FP_FAST_FMAF32x 1\n#define __FLT128_DECIMAL_DIG__ 36\n#define __GCC_ATOMIC_LLONG_LOCK_FREE 2\n#define __FLT_DECIMAL_DIG__ 9\n#define __UINT_FAST16_MAX__ 0xffff\n#define __LDBL_NORM_MAX__ 1.79769313486231570814527423731704357e+308L\n#define __FLT_MIN_10_EXP__ (-37)\n#define __GCC_ATOMIC_SHORT_LOCK_FREE 2\n#define __ORDER_LITTLE_ENDIAN__ 1234\n#define __WCHAR_MAX__ 0x7fffffff\n#define __UINT_LEAST32_MAX__ 0xffffffffU\n#define __ATOMIC_ACQ_REL 4\n", + "flags": "-ffast-math", + "compiler": "gcc-16 (Homebrew GCC 16.2.0) 16.2.0", + "target": "aarch64-apple-darwin24", + "about": "The flag that tells the library your arithmetic is a lie" + } + }, + "expansions": { + "spacing": { + "about": "A space in the output that is in none of the input, twice over", + "source": "#define EMPTY\n#define PLUS +\na+EMPTY+b\na PLUS +b\na+ +b\n", + "output": "a+ +b\na + +b\na+ +b\n", + "elsewhere": "a+ +b\na + +b\na+ +b\n" + }, + "prescan": { + "about": "Why stringifying a macro takes two macros, and what the first one is for", + "source": "#define PLUS +\n#define STR(x) #x\n#define XSTR(x) STR(x)\nSTR(PLUS)\nXSTR(PLUS)\n", + "output": "\"PLUS\"\n\"+\"\n", + "elsewhere": "\"PLUS\"\n\"+\"\n" + }, + "paste": { + "about": "The one operator that makes two tokens into one, and what it costs", + "source": "#define CAT(x, y) x ## y\n#define PLUS +\nCAT(a, b)\nCAT(PLUS, PLUS)\n", + "output": "ab\nPLUSPLUS\n", + "elsewhere": "ab\nPLUSPLUS\n" + }, + "paint": { + "about": "A macro that names itself, and one that names a macro that names it back", + "source": "#define foo foo + 1\n#define A B\n#define B A\nfoo\nA\n", + "output": "foo + 1\nA\n", + "elsewhere": "foo + 1\nA\n" + }, + "invocation": { + "about": "A function-like macro is not expanded unless the next token is an open bracket", + "source": "#define f(x) [x]\nf(1)\nf\nf (2)\n", + "output": "[1]\nf\n[2]\n", + "elsewhere": "[1]\nf\n[2]\n" + }, + "markers": { + "about": "The same file with the line markers left in, which is the default", + "source": "#include \"clean.h\"\nint before;\n#include \"stray.h\"\nint after;\n", + "output": "# 0 \"markers.c\"\n# 0 \"\"\n# 0 \"\"\n# 1 \"markers.c\"\n# 1 \"clean.h\" 1\n\n\nint clean_thing;\n# 2 \"markers.c\" 2\nint before;\n# 1 \"stray.h\" 1\n\n\nint stray_thing;\n\ntypedef int stray_t;\n# 4 \"markers.c\" 2\nint after;\n", + "elsewhere": "" + } + }, + "probes": [ + { + "left": ">", + "right": ">", + "case": "CPP_GREATER", + "about": "or it would be a right shift", + "output": "> >" + }, + { + "left": "<", + "right": "<", + "case": "CPP_LESS", + "about": "or it would be a left shift", + "output": "< <" + }, + { + "left": "<", + "right": ":", + "case": "CPP_LESS", + "about": "or it would be the digraph for an open bracket", + "output": "< :" + }, + { + "left": "+", + "right": "+", + "case": "CPP_PLUS", + "about": "or it would be an increment", + "output": "+ +" + }, + { + "left": "-", + "right": "-", + "case": "CPP_MINUS", + "about": "or it would be a decrement", + "output": "- -" + }, + { + "left": "-", + "right": ">", + "case": "CPP_MINUS", + "about": "or it would be a member access", + "output": "- >" + }, + { + "left": "/", + "right": "/", + "case": "CPP_DIV", + "about": "or it would be a comment, and eat the rest of the line", + "output": "/ /" + }, + { + "left": "/", + "right": "*", + "case": "CPP_DIV", + "about": "or it would open a comment that nobody closes", + "output": "/ *" + }, + { + "left": "%", + "right": ">", + "case": "CPP_MOD", + "about": "or it would be the digraph for a close brace", + "output": "% >" + }, + { + "left": "&", + "right": "&", + "case": "CPP_AND", + "about": "or it would be a logical and", + "output": "& &" + }, + { + "left": "|", + "right": "|", + "case": "CPP_OR", + "about": "or it would be a logical or", + "output": "| |" + }, + { + "left": ":", + "right": ">", + "case": "CPP_COLON", + "about": "or it would be the digraph for a close bracket", + "output": ": >" + }, + { + "left": "->", + "right": "*", + "case": "CPP_DEREF", + "about": "or it would be a pointer to member, which C++ has", + "output": "-> *" + }, + { + "left": ".", + "right": ".", + "case": "CPP_DOT", + "about": "two of three characters of an ellipsis", + "output": ". ." + }, + { + "left": ".", + "right": "5", + "case": "CPP_DOT", + "about": "or it would be the number .5", + "output": ". 5" + }, + { + "left": "<=", + "right": ">", + "case": "CPP_LESS_EQ", + "about": "or it would be the spaceship operator", + "output": "<= >" + }, + { + "left": "+", + "right": "=", + "case": "CPP_LAST_EQ", + "about": "or it would be a compound assignment", + "output": "+ =" + }, + { + "left": "!", + "right": "=", + "case": "CPP_LAST_EQ", + "about": "or it would be a comparison, which is the opposite", + "output": "! =" + }, + { + "left": "x", + "right": "y", + "case": "CPP_NAME", + "about": "or it would be one identifier called xy", + "output": "x y" + }, + { + "left": "x", + "right": "5", + "case": "CPP_NAME", + "about": "or it would be one identifier called x5", + "output": "x 5" + }, + { + "left": "L", + "right": "'c'", + "case": "CPP_NAME", + "about": "or it would be a wide character literal", + "output": "L 'c'" + }, + { + "left": "L", + "right": "\"s\"", + "case": "CPP_NAME", + "about": "or it would be a wide string literal", + "output": "L \"s\"" + }, + { + "left": "1", + "right": "2", + "case": "CPP_NUMBER", + "about": "or it would be twelve", + "output": "1 2" + }, + { + "left": "1", + "right": "x", + "case": "CPP_NUMBER", + "about": "or it would be a number with a suffix on it", + "output": "1 x" + }, + { + "left": "1", + "right": ".", + "case": "CPP_NUMBER", + "about": "or it would be a floating point number", + "output": "1 ." + }, + { + "left": "1", + "right": "+", + "case": "CPP_NUMBER", + "about": "or it would be an exponent, in a number like 1e+5", + "output": "1 +" + }, + { + "left": "\\", + "right": "x", + "case": "CPP_OTHER", + "about": "or it would be a universal character name", + "output": "\\ x" + }, + { + "left": "#", + "right": "#", + "case": "CPP_HASH", + "about": "or it would be a paste operator", + "output": " # #" + }, + { + "left": "#", + "right": "%", + "case": "CPP_HASH", + "about": "or it would be the digraph for a paste operator", + "output": " # %" + }, + { + "left": "+", + "right": "-", + "case": "", + "about": "nothing, and that is the point", + "output": "+-" + }, + { + "left": "x", + "right": "+", + "case": "", + "about": "nothing, and that is the point", + "output": "x+" + }, + { + "left": "*", + "right": "&", + "case": "", + "about": "nothing, and that is the point", + "output": "*&" + }, + { + "left": "]", + "right": "[", + "case": "", + "about": "nothing, and that is the point", + "output": "][" + }, + { + "left": ";", + "right": ";", + "case": "", + "about": "nothing, and that is the point", + "output": ";;" + }, + { + "left": "&", + "right": "|", + "case": "", + "about": "nothing, and that is the point", + "output": "&|" + }, + { + "left": "!", + "right": "!", + "case": "", + "about": "nothing, and that is the point", + "output": "!!" + }, + { + "left": "~", + "right": "x", + "case": "", + "about": "nothing, and that is the point", + "output": "~x" + }, + { + "left": "1", + "right": "]", + "case": "", + "about": "nothing, and that is the point", + "output": "1]" + } + ], + "headers": { + "local": { + "text": ". /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/stdio.h\n.. /opt/homebrew/Cellar/gcc/16.2.0/lib/gcc/current/gcc/aarch64-apple-darwin24/16/include-fixed/_stdio.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/_bounds.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/cdefs.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_symbol_aliasing.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_posix_availability.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/Availability.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/AvailabilityVersions.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/AvailabilityInternal.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/AvailabilityVersions.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/AvailabilityInternalLegacy.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/AvailabilityInternal.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/_types.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/machine/_types.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/arm/_types.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_pthread/_pthread_types.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_va_list.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/machine/types.h\n..... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/arm/types.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_int8_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_int16_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_int32_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_int64_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_u_int8_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_u_int16_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_u_int32_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_u_int64_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_intptr_t.h\n...... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_uintptr_t.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_size_t.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_null.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/stdio.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/Availability.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/_printf.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_seek_set.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/_ctermid.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_off_t.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_ssize_t.h\n... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/secure/_stdio.h\n.... /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/secure/_common.h\n. /Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/stdio.h\nMultiple include guards may be useful for:\n/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/secure/_stdio.h\n/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_posix_availability.h\n/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_symbol_aliasing.h\n/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_null.h\n/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/sys/_types/_size_t.h\n", + "about": "One #include , on a machine with an Apple SDK on it" + }, + "elsewhere": { + "text": ". /usr/include/stdio.h\n.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h\n... /usr/include/features.h\n.... /usr/include/features-time64.h\n..... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n..... /usr/include/x86_64-linux-gnu/bits/timesize.h\n...... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n.... /usr/include/x86_64-linux-gnu/sys/cdefs.h\n..... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n..... /usr/include/x86_64-linux-gnu/bits/long-double.h\n.... /usr/include/x86_64-linux-gnu/gnu/stubs.h\n..... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h\n.. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h\n.. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stdarg.h\n.. /usr/include/x86_64-linux-gnu/bits/types.h\n... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n... /usr/include/x86_64-linux-gnu/bits/timesize.h\n.... /usr/include/x86_64-linux-gnu/bits/wordsize.h\n... /usr/include/x86_64-linux-gnu/bits/typesizes.h\n... /usr/include/x86_64-linux-gnu/bits/time64.h\n.. /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h\n... /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h\n.. /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h\n.. /usr/include/x86_64-linux-gnu/bits/types/__FILE.h\n.. /usr/include/x86_64-linux-gnu/bits/types/FILE.h\n.. /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h\n.. /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h\n.. /usr/include/x86_64-linux-gnu/bits/stdio_lim.h\n.. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn.h\n... /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn-common.h\n.... /usr/include/x86_64-linux-gnu/bits/long-double.h\nMultiple include guards may be useful for:\n/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h\n/usr/include/features-time64.h\n/usr/include/x86_64-linux-gnu/bits/libc-header-start.h\n/usr/include/x86_64-linux-gnu/bits/time64.h\n/usr/include/x86_64-linux-gnu/bits/typesizes.h\n/usr/include/x86_64-linux-gnu/gnu/stubs-64.h\n/usr/include/x86_64-linux-gnu/gnu/stubs.h", + "about": "The same two lines on x86-64 Linux, where the headers are glibc's" + }, + "guards": { + "text": ". clean.h\n. untidy.h\n. stray.h\n. stray.h\n. bare.h\n. bare.h\n", + "about": "Four headers of this lesson's own, each one included twice" + }, + "once": { + "text": ". clean.h\n. untidy.h\n. stray.h\n. bare.h\nMultiple include guards may be useful for:\nbare.h\nstray.h\n", + "about": "The same four, each included once, which is when GCC gives advice" + } + }, + "builtin": { + "array": [ + "__TIMESTAMP__", + "__TIME__", + "__DATE__", + "__FILE__", + "__FILE_NAME__", + "__BASE_FILE__", + "__LINE__", + "__INCLUDE_LEVEL__", + "__COUNTER__", + "__has_attribute", + "__has_c_attribute", + "__has_cpp_attribute", + "__has_builtin", + "__has_include", + "__has_include_next", + "__has_embed", + "__has_feature", + "__has_extension", + "_Pragma", + "__STDC__" + ], + "fixed": [ + "__ASSEMBLER__", + "__OBJC__", + "__STDC_EMBED_EMPTY__", + "__STDC_EMBED_FOUND__", + "__STDC_EMBED_NOT_FOUND__", + "__STDC_HOSTED__", + "__STDC_UTF_16__", + "__STDC_UTF_32__", + "__STDC_VERSION__", + "__STDC__", + "__cplusplus" + ] + } +} diff --git a/corpora/source/f02.json b/corpora/source/f02.json new file mode 100644 index 0000000..b0d9b35 --- /dev/null +++ b/corpora/source/f02.json @@ -0,0 +1,339 @@ +{ + "tag": "releases/gcc-16.2.0", + "snippets": { + "padding": { + "path": "libcpp/include/cpplib.h", + "first": 152, + "last": 164, + "about": "The end of the token type list, and the one that is whitespace", + "lines": [ + " TK(COMMENT,\t\tLITERAL) /* Only if output comments. */\t\\", + "\t\t\t\t /* SPELL_LITERAL happens to DTRT. */\t\\", + " TK(MACRO_ARG,\t\tNONE)\t /* Macro argument. */\t\t\t\\", + " TK(PRAGMA,\t\tNONE)\t /* Only for deferred pragmas. */\t\\", + " TK(PRAGMA_EOL,\tNONE)\t /* End-of-line for deferred pragmas. */ \\", + " TK(PADDING,\t\tNONE)\t /* Whitespace for -E.\t*/", + "", + "#define OP(e, s) CPP_ ## e,", + "#define TK(e, s) CPP_ ## e,", + "enum cpp_ttype", + "{", + " TTYPE_TABLE", + " N_TTYPES," + ] + }, + "token": { + "path": "libcpp/include/cpplib.h", + "first": 261, + "last": 294, + "about": "What a token is: a location, a type, some flags, and one union", + "lines": [ + "/* A preprocessing token. This occupies 32 bytes on a 64-bit host. On a", + " 32-bit host it occupies 20 or 24 bytes, depending whether a uint64_t", + " requires 4- or 8-byte alignment. */", + "", + "struct GTY(()) cpp_token {", + "", + " /* Location of first char of token, together with range of full token. */", + " location_t src_loc;", + "", + " ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */", + " unsigned short flags;\t\t/* flags - see above */", + "", + " union cpp_token_u", + " {", + " /* An identifier. */", + " struct cpp_identifier GTY ((tag (\"CPP_TOKEN_FLD_NODE\"))) node;", + "", + " /* Inherit padding from this token. */", + " cpp_token * GTY ((tag (\"CPP_TOKEN_FLD_SOURCE\"))) source;", + "", + " /* A string, or number. */", + " struct cpp_string GTY ((tag (\"CPP_TOKEN_FLD_STR\"))) str;", + "", + " /* Argument no. (and original spelling) for a CPP_MACRO_ARG. */", + " struct cpp_macro_arg GTY ((tag (\"CPP_TOKEN_FLD_ARG_NO\"))) macro_arg;", + "", + " /* Original token no. for a CPP_PASTE (from a sequence of", + " consecutive paste tokens in a macro expansion). */", + " unsigned int GTY ((tag (\"CPP_TOKEN_FLD_TOKEN_NO\"))) token_no;", + "", + " /* Caller-supplied identifier for a CPP_PRAGMA. */", + " unsigned int GTY ((tag (\"CPP_TOKEN_FLD_PRAGMA\"))) pragma;", + " } GTY ((desc (\"cpp_token_val_index (&%1)\"))) val;", + "};" + ] + }, + "avoid-paste": { + "path": "libcpp/lex.cc", + "first": 4723, + "last": 4791, + "about": "The whole rule for which two tokens cannot be printed next to each other", + "lines": [ + "/* Returns nonzero if a space should be inserted to avoid an", + " accidental token paste for output. For simplicity, it is", + " conservative, and occasionally advises a space where one is not", + " needed, e.g. \".\" and \".2\". */", + "int", + "cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1,", + "\t\t const cpp_token *token2)", + "{", + " enum cpp_ttype a = token1->type, b = token2->type;", + " cppchar_t c;", + "", + " if (token1->flags & NAMED_OP)", + " a = CPP_NAME;", + " if (token2->flags & NAMED_OP)", + " b = CPP_NAME;", + "", + " c = EOF;", + " if (token2->flags & DIGRAPH)", + " c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0];", + " else if (token_spellings[b].category == SPELL_OPERATOR)", + " c = token_spellings[b].name[0];", + "", + " /* Quickly get everything that can paste with an '='. */", + " if ((int) a <= (int) CPP_LAST_EQ && c == '=')", + " return 1;", + "", + " switch (a)", + " {", + " case CPP_GREATER:\treturn c == '>';", + " case CPP_LESS:\treturn c == '<' || c == '%' || c == ':';", + " case CPP_PLUS:\treturn c == '+';", + " case CPP_MINUS:\treturn c == '-' || c == '>';", + " case CPP_DIV:\treturn c == '/' || c == '*'; /* Comments. */", + " case CPP_MOD:\treturn c == ':' || c == '>';", + " case CPP_AND:\treturn c == '&';", + " case CPP_OR:\treturn c == '|';", + " case CPP_COLON:\treturn c == ':' || c == '>';", + " case CPP_DEREF:\treturn c == '*';", + " case CPP_DOT:\treturn c == '.' || c == '%' || b == CPP_NUMBER;", + " case CPP_HASH:\treturn c == '#' || c == '%'; /* Digraph form. */", + " case CPP_PRAGMA:", + " case CPP_NAME:\treturn ((b == CPP_NUMBER", + "\t\t\t\t && name_p (pfile, &token2->val.str))", + "\t\t\t\t|| b == CPP_NAME", + "\t\t\t\t|| b == CPP_CHAR || b == CPP_STRING); /* L */", + " case CPP_NUMBER:\treturn (b == CPP_NUMBER || b == CPP_NAME", + "\t\t\t\t|| b == CPP_CHAR", + "\t\t\t\t|| c == '.' || c == '+' || c == '-');", + "\t\t\t\t /* UCNs */", + " case CPP_OTHER:\treturn ((token1->val.str.text[0] == '\\\\'", + "\t\t\t\t && b == CPP_NAME)", + "\t\t\t\t|| (CPP_OPTION (pfile, objc)", + "\t\t\t\t && token1->val.str.text[0] == '@'", + "\t\t\t\t && (b == CPP_NAME || b == CPP_STRING)));", + " case CPP_LESS_EQ:\treturn c == '>';", + " case CPP_STRING:", + " case CPP_WSTRING:", + " case CPP_UTF8STRING:", + " case CPP_STRING16:", + " case CPP_STRING32:\treturn (CPP_OPTION (pfile, user_literals)", + "\t\t\t\t&& (b == CPP_NAME", + "\t\t\t\t || (TOKEN_SPELL (token2) == SPELL_LITERAL", + "\t\t\t\t\t&& ISIDST (token2->val.str.text[0]))));", + "", + " default:\t\tbreak;", + " }", + "", + " return 0;", + "}" + ] + }, + "spacing": { + "path": "gcc/c-family/c-ppoutput.cc", + "first": 244, + "last": 268, + "about": "The three reasons a space is printed, and the comment that admits it", + "lines": [ + " /* Subtle logic to output a space if and only if necessary. */", + " bool line_marker_emitted = false;", + " if (avoid_paste)", + " {", + " unsigned src_line = LOCATION_LINE (loc);", + "", + " if (print.source == NULL)", + "\tprint.source = token;", + "", + " if (src_line != print.src_line", + "\t && do_line_adjustments", + "\t && !in_pragma)", + "\t{", + "\t line_marker_emitted = do_line_change (pfile, token, loc, false);", + "\t putc (' ', print.outf);", + "\t print.printed = true;", + "\t}", + " else if (print.source->flags & PREV_WHITE", + "\t || (print.prev", + "\t\t && cpp_avoid_paste (pfile, print.prev, token))", + "\t || (print.prev == NULL && token->type == CPP_HASH))", + "\t{", + "\t putc (' ', print.outf);", + "\t print.printed = true;", + "\t}" + ] + }, + "markers": { + "path": "gcc/c-family/c-ppoutput.cc", + "first": 618, + "last": 628, + "about": "Where a line marker comes from, and the two digits nothing passes in", + "lines": [ + " fprintf (stream, \"# %u \\\"%s\\\"%s\",", + "\t print.src_line, to_file_quoted, special_flags);", + "", + " int sysp = in_system_header_at (src_loc);", + " if (sysp == 2)", + "\tfputs (\" 3 4\", stream);", + " else if (sysp == 1)", + "\tfputs (\" 3\", stream);", + "", + " putc ('\\n', stream);", + " emitted_line_marker = true;" + ] + }, + "marker-flags": { + "path": "gcc/doc/cpp.texi", + "first": 4072, + "last": 4088, + "about": "What each digit means, from the one place in the tree that says so", + "lines": [ + "After the file name comes zero or more flags, which are @samp{1},", + "@samp{2}, @samp{3}, or @samp{4}. If there are multiple flags, spaces", + "separate them. Here is what the flags mean:", + "", + "@table @samp", + "@item 1", + "This indicates the start of a new file.", + "@item 2", + "This indicates returning to a file (after having included another file).", + "@item 3", + "This indicates that the following text comes from a system header file,", + "so certain warnings should be suppressed.", + "@item 4", + "This indicates that the following text should be treated as being", + "wrapped in an implicit @code{extern \"C\"} block.", + "@c maybe cross reference SYSTEM_IMPLICIT_EXTERN_C", + "@end table" + ] + }, + "dump": { + "path": "gcc/c-family/c-ppoutput.cc", + "first": 903, + "last": 918, + "about": "Why -dM does not print the five macros everybody can name", + "lines": [ + "/* Dump out the hash table. */", + "static int", + "dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)", + "{", + " if (cpp_user_macro_p (node))", + " {", + " fputs (\"#define \", print.outf);", + " fputs ((const char *) cpp_macro_definition (pfile, node),", + "\t print.outf);", + " putc ('\\n', print.outf);", + " print.printed = false;", + " print.src_line++;", + " }", + "", + " return 1;", + "}" + ] + }, + "builtins": { + "path": "libcpp/init.cc", + "first": 448, + "last": 476, + "about": "The macros that are C functions, because no string could be right", + "lines": [ + "#define B(n, t, f) { DSC(n), t, f }", + "static const struct builtin_macro builtin_array[] =", + "{", + " B(\"__TIMESTAMP__\",\t BT_TIMESTAMP, false),", + " B(\"__TIME__\",\t\t BT_TIME, false),", + " B(\"__DATE__\",\t\t BT_DATE, false),", + " B(\"__FILE__\",\t\t BT_FILE, false),", + " B(\"__FILE_NAME__\",\t BT_FILE_NAME, false),", + " B(\"__BASE_FILE__\",\t BT_BASE_FILE, false),", + " B(\"__LINE__\",\t\t BT_SPECLINE, true),", + " B(\"__INCLUDE_LEVEL__\", BT_INCLUDE_LEVEL, true),", + " B(\"__COUNTER__\",\t BT_COUNTER, true),", + " /* Make sure to update the list of built-in", + " function-like macros in traditional.cc:", + " fun_like_macro() when adding more following */", + " B(\"__has_attribute\",\t BT_HAS_ATTRIBUTE, true),", + " B(\"__has_c_attribute\", BT_HAS_STD_ATTRIBUTE, true),", + " B(\"__has_cpp_attribute\", BT_HAS_ATTRIBUTE, true),", + " B(\"__has_builtin\",\t BT_HAS_BUILTIN, true),", + " B(\"__has_include\",\t BT_HAS_INCLUDE, true),", + " B(\"__has_include_next\",BT_HAS_INCLUDE_NEXT, true),", + " B(\"__has_embed\",\t BT_HAS_EMBED, true),", + " B(\"__has_feature\",\t BT_HAS_FEATURE, true),", + " B(\"__has_extension\",\t BT_HAS_EXTENSION, true),", + " /* Keep builtins not used for -traditional-cpp at the end, and", + " update init_builtins() if any more are added. */", + " B(\"_Pragma\",\t\t BT_PRAGMA, true),", + " B(\"__STDC__\",\t\t BT_STDC, true),", + "};" + ] + }, + "paint": { + "path": "libcpp/macro.cc", + "first": 1589, + "last": 1590, + "about": "Two lines, and the reason a macro that names itself terminates", + "lines": [ + " /* Disable the macro within its expansion. */", + " node->flags |= NODE_DISABLED;" + ] + }, + "guard": { + "path": "libcpp/files.cc", + "first": 858, + "last": 861, + "about": "The include guard optimization, which is one comment and one condition", + "lines": [ + " /* Skip if the file had a header guard and the macro is defined.", + " PCH relies on this appearing before the PCH handler below. */", + " if (file->cmacro && cpp_macro_p (file->cmacro))", + " return true;" + ] + }, + "advice": { + "path": "libcpp/files.cc", + "first": 2214, + "last": 2219, + "about": "Who gets told to write a guard, and the condition that means it is not you", + "lines": [ + " /* We don't want MI guard advice for the main file. */", + " if (!file->once_only", + "\t && file->cmacro == NULL", + "\t && file->stack_count == 1", + "\t && data->pfile->main_file != file)", + "\t{" + ] + }, + "trace": { + "path": "libcpp/line-map.cc", + "first": 1589, + "last": 1600, + "about": "What -H prints, and the reason a skipped file leaves no line", + "lines": [ + "/* Print an include trace, for e.g. the -H option of the preprocessor. */", + "", + "static void", + "trace_include (const class line_maps *set, const line_map_ordinary *map)", + "{", + " unsigned int i = set->depth;", + "", + " while (--i)", + " putc ('.', stderr);", + "", + " fprintf (stderr, \" %s\\n\", ORDINARY_MAP_FILE_NAME (map));", + "}" + ] + } + } +} diff --git a/docs/blueprints.md b/docs/blueprints.md index 7335771..8601afa 100644 --- a/docs/blueprints.md +++ b/docs/blueprints.md @@ -13,6 +13,7 @@ The pseudocode every algorithm is written in is [NOTATION](blueprints/NOTATION.m | [BP-BOOTSTRAP](blueprints/BP-BOOTSTRAP.md) | building the compiler with itself | partial | 2 of 9 | no | | [BP-BUILD](blueprints/BP-BUILD.md) | configuring and building the compiler | partial | 2 of 9 | yes | | [BP-CFG](blueprints/BP-CFG.md) | blocks and edges | stub | none | no | +| [BP-CPP](blueprints/BP-CPP.md) | the preprocessor | partial | none | yes | | [BP-DEBUGGING](blueprints/BP-DEBUGGING.md) | stopping the compiler and looking at it | complete | 2 of 9 | no | | [BP-DRIVER](blueprints/BP-DRIVER.md) | the program that runs the other programs | partial | none | yes | | [BP-EXPAND](blueprints/BP-EXPAND.md) | GIMPLE becomes RTL | stub | none | yes | @@ -25,7 +26,7 @@ The pseudocode every algorithm is written in is [NOTATION](blueprints/NOTATION.m | [BP-SSA](blueprints/BP-SSA.md) | one definition per name | stub | none | no | | [BP-TESTSUITE](blueprints/BP-TESTSUITE.md) | running GCC's own tests | partial | 2 of 9 | yes | -14 of 58 written: 2 complete, 6 partial, 6 stub. +15 of 58 written: 2 complete, 7 partial, 6 stub. ## What each one is for @@ -41,6 +42,10 @@ This document specifies what happens between a source tree and a working `cc1`. This is a stub. It holds the data structures, the two fixed blocks, how a GIMPLE sequence becomes a graph, and what dominance is computed by and when it is valid. The pass level detail is not here: loop discovery, profile propagation, hot and cold partitioning, and the RTL side of the hooks are named and not specified. Section 2.3 could be generated from `gcc/cfg-flags.def`, which is a `.def` file with exactly the shape `bpc` reads, and that is the obvious first thing to do when this stub is promoted. +### [BP-CPP](blueprints/BP-CPP.md), the preprocessor + +This document specifies libcpp, the library that turns a source file into a stream of preprocessing tokens, and the client in `gcc/c-family/c-ppoutput.cc` that prints that stream when you ask for `-E`. The token, the token type table, the hash node and the macro are specified field by field. Lexing, macro expansion, argument prescan, stringification, pasting, the disabling rule, the multiple include optimization and the spacing rule the printer applies are specified as algorithms. Traditional mode, modules and header units, precompiled headers, `#embed`, character set conversion and the `#if` expression evaluator are named and not specified, and each place that stops short says so. Nothing here is generated, because libcpp keeps its tables in C macros rather than in `.def` files a script could read without a C parser. What exists instead is `gxray.cpp`, a reader for recorded preprocessor output, with tests that compare its table of paste-avoiding pairs against the case labels of `cpp_avoid_paste` in the pinned tree, so a GCC that grows a pair fails the build rather than making a paragraph quietly false. + ### [BP-DEBUGGING](blueprints/BP-DEBUGGING.md), stopping the compiler and looking at it This document specifies the interfaces GCC provides for inspecting a compiler while it is running, and the two non interactive substitutes for doing so. It covers the `.gdbinit` that `configure` writes, the twenty six commands and four Python commands in it, the seventeen pretty printers, the debug counters behind `-fdbg-cnt`, and the pass selection options that decide what runs at all. diff --git a/docs/blueprints/BP-CPP.md b/docs/blueprints/BP-CPP.md new file mode 100644 index 0000000..7047d7a --- /dev/null +++ b/docs/blueprints/BP-CPP.md @@ -0,0 +1,3 @@ + + +--8<-- "blueprints/BP-CPP.md" diff --git a/docs/lessons.md b/docs/lessons.md index 3c39423..d68377b 100644 --- a/docs/lessons.md +++ b/docs/lessons.md @@ -24,5 +24,6 @@ Every one is a notebook with a Colab badge, so there is nothing to install. Part | B04 | [Forty thousand tests, and how to run one of them](https://github.com/tamnd/gcc-internals/blob/main/lessons/b04-the-test-suite/b04.ipynb) | The GCC test suite taken apart: what a directive is, why the command line is not what the file says, the subtractive rule that makes a test fail for output nobody asked about, the six compilations every torture test costs, how to run one file without running the other thirty five thousand, and the one question worth asking of a .sum | M2 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/b04-the-test-suite/b04.ipynb) | | B05 | [Sixty lines of C++, and you are inside the compiler](https://github.com/tamnd/gcc-internals/blob/main/lessons/b05-the-plugin/b05.ipynb) | GCC's plugin mechanism from the outside in: the three things a plugin has to have, the three ways it is refused, what an event actually is, a GIMPLE pass of your own inserted after ssa with its own dump file, switching one of GCC's passes off from outside and watching the assembly move, and why the thing you are writing against is not an API | M2 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/b05-the-plugin/b05.ipynb) | | F01 | [The driver is an interpreter](https://github.com/tamnd/gcc-internals/blob/main/lessons/f01-the-spec-language/f01.ipynb) | That `gcc -dumpspecs` prints a program, in a language with conditionals and function calls, which the driver interprets to decide what to run; how to read it; and four text files that change what your compiler does without patching or rebuilding it | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/f01-the-spec-language/f01.ipynb) | +| F02 | [The preprocessor is not a text editor](https://github.com/tamnd/gcc-internals/blob/main/lessons/f02-tokens-not-text/f02.ipynb) | That the preprocessor lexes your file into tokens before it does anything else, and that its printed output is a rendering of those tokens rather than the tokens themselves; the space GCC inserts that is in no input file; the four hundred macros you did not write; and why one #include of stdio.h opens thirty eight files | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/f02-tokens-not-text/f02.ipynb) | -18 of 96 written. +19 of 96 written. diff --git a/gxray/cpp.py b/gxray/cpp.py new file mode 100644 index 0000000..9aaf877 --- /dev/null +++ b/gxray/cpp.py @@ -0,0 +1,643 @@ +"""What the preprocessor prints, read back as the tokens it actually was. + +`gcc -E` looks like text going in and text coming out, and that reading survives right up +until the first time it does not. This module reads the four things the preprocessor will +tell you about itself: + + from gxray import cpp + rec = cpp.load("f02") + + rec.macros("local") # 443 macros nobody wrote + rec.macros("local").only_in(rec.macros("elsewhere")) # the ones that are this target + cpp.markers(rec.expansion("markers").output) # every `# 1 "file"` line + cpp.parse_trace(rec.headers("local").text).files # 38 files for one #include + +Like `gxray.specs`, this is a reader and not a second implementation. It never expands a +macro. Expanding one needs the include path, the target's macros, the date, the file being +compiled and a hash table with the state of every other macro in it, and a lesson that faked +those would be teaching a fiction. + +The one table here that is a claim about GCC rather than about its output is `PASTES`, which +is the pairs of adjacent tokens `cpp_avoid_paste` puts a space between at +`libcpp/lex.cc:4728@releases/gcc-16.2.0`. Every row names the `case` label it comes from, and +a test compares the set of labels against the switch in the pinned tree, so a GCC that learns +a new pair fails the build rather than quietly making a sentence wrong. That space is the +whole lesson: it is a character in the output that is in no input file, and it is there +because two tokens would otherwise lex as one. +""" + +from __future__ import annotations + +import json +import re +from dataclasses import dataclass, field +from pathlib import Path + +#: Where a recording of one compiler's preprocessor lives. +CORPUS = Path(__file__).resolve().parent.parent / "corpora" / "cpp" + + +class CppError(Exception): + """Something asked of a preprocessor recording that it cannot answer.""" + + +# --------------------------------------------------------------------------- +# Line markers +# --------------------------------------------------------------------------- + +#: What the digits after a line marker mean. GCC writes them in `print_line_1` at +#: `gcc/c-family/c-ppoutput.cc:592@releases/gcc-16.2.0`, and a reader who does not know them +#: reads `# 1 "/usr/include/stdio.h" 1 3 4` as noise rather than as the four facts it is. +MARKER_FLAGS: dict[int, str] = { + 1: "entering a file", + 2: "returning to a file", + 3: "a system header, where warnings are suppressed", + 4: 'to be wrapped in extern "C"', +} + +#: `# 61 "stdio.h" 2 3 4`. The quotes are always there and the flags never are. +MARKER = re.compile(r'^#\s+(?P\d+)\s+"(?P(?:[^"\\]|\\.)*)"(?P[\s\d]*)$') + + +@dataclass(frozen=True) +class Marker: + """One `# line "file" flags` line of preprocessed output. + + Not a comment and not a directive: it is how the preprocessor hands the parser back the + line numbers it just destroyed. Everything after it came from `file` starting at `line`, + and that is what makes an error message in a header point at the header. + """ + + line: int + file: str + flags: tuple[int, ...] + + @property + def entering(self) -> bool: + return 1 in self.flags + + @property + def returning(self) -> bool: + return 2 in self.flags + + @property + def system(self) -> bool: + return 3 in self.flags + + @property + def meanings(self) -> list[str]: + return [MARKER_FLAGS[flag] for flag in self.flags if flag in MARKER_FLAGS] + + def __str__(self) -> str: + said = ", ".join(self.meanings) or "no flags, so the line number moved and nothing else" + return f"{self.file}:{self.line} ({said})" + + +def markers(text: str) -> list[Marker]: + """Every line marker in a chunk of `-E` output, in the order they were printed.""" + found = [] + for line in text.split("\n"): + got = MARKER.match(line) + if got: + flags = tuple(int(n) for n in got["flags"].split()) + found.append(Marker(line=int(got["line"]), file=got["file"], flags=flags)) + return found + + +def body(text: str) -> list[str]: + """The output with its line markers and its blank lines taken out. + + Which is usually a much shorter file than the reader expected, and is the point of + printing the length of both. + """ + return [line for line in text.split("\n") if line.strip() and not MARKER.match(line)] + + +# --------------------------------------------------------------------------- +# Macro tables +# --------------------------------------------------------------------------- + +#: One line of `-dM -E` output. The name runs to a space or an open bracket, and a bracket +#: touching the name is what makes a macro function-like: `#define f (x) x` defines `f` as +#: `(x) x`, and getting that wrong is a rite of passage rather than a corner case. +DEFINE = re.compile( + r"^#define\s+(?P[A-Za-z_$][\w$]*)(?P\([^)]*\))?(?: (?P.*))?$" +) + + +@dataclass(frozen=True) +class Macro: + """One macro, as `-dM` prints it.""" + + name: str + params: str | None + body: str + + @property + def function_like(self) -> bool: + return self.params is not None + + @property + def empty(self) -> bool: + """Defined and expanding to nothing, which is not the same as not defined.""" + return self.body == "" + + def __str__(self) -> str: + head = f"{self.name}{self.params or ''}" + return f"{head} {self.body}".rstrip() + + +@dataclass +class Macros: + """Every macro a compiler defines before it has read a line of your program. + + A mapping, but the interesting operations are the set ones. One of these tables on its + own is a wall of names. Two of them, from two targets, sort themselves into what C + guarantees, what GCC adds, and what the machine underneath is admitting to. + """ + + text: str + entries: dict[str, Macro] + flags: str = "" + compiler: str = "" + target: str = "" + about: str = "" + + def __len__(self) -> int: + return len(self.entries) + + def __contains__(self, name: object) -> bool: + return name in self.entries + + def __iter__(self): + return iter(self.entries.values()) + + def __getitem__(self, name: str) -> Macro: + if name not in self.entries: + raise CppError(f"{name} is not defined on {self.target or 'this target'}") + return self.entries[name] + + @property + def names(self) -> list[str]: + return sorted(self.entries) + + @property + def function_like(self) -> list[str]: + return sorted(one.name for one in self if one.function_like) + + @property + def empty(self) -> list[str]: + return sorted(one.name for one in self if one.empty) + + def starting(self, *prefixes: str) -> list[str]: + return sorted(n for n in self.entries if n.startswith(prefixes)) + + def only_in(self, other: Macros) -> list[str]: + """Names this table has and the other does not.""" + return sorted(set(self.entries) - set(other.entries)) + + def shared(self, other: Macros) -> list[str]: + return sorted(set(self.entries) & set(other.entries)) + + def differing(self, other: Macros) -> list[str]: + """Names both tables define, to different things, which is the awkward set. + + A macro missing on the other target is a thing `#ifdef` can see. A macro defined on + both with a different value is a thing only arithmetic can see, and it is where the + portability bugs live. + """ + return sorted( + name + for name in set(self.entries) & set(other.entries) + if self.entries[name].body != other.entries[name].body + ) + + def __str__(self) -> str: + where = self.target or "somewhere" + return f"{len(self)} macros on {where}{' with ' + self.flags if self.flags else ''}" + + +def parse_macros(text: str, **about) -> Macros: + """Read `gcc -dM -E` output. Anything that is not a `#define` line is an error. + + Strict on purpose. The whole value of this table is that it is exhaustive, so a line + this cannot read is a line the count is wrong about. + """ + entries: dict[str, Macro] = {} + for line in text.split("\n"): + if not line.strip(): + continue + got = DEFINE.match(line) + if not got: + raise CppError(f"-dM printed a line that is not a definition: {line!r}") + entries[got["name"]] = Macro(name=got["name"], params=got["params"], body=got["body"] or "") + return Macros(text=text, entries=entries, **about) + + +# --------------------------------------------------------------------------- +# Include traces +# --------------------------------------------------------------------------- + +#: A `-H` line: one dot per level of nesting, a space, and the path. The dots are written by +#: `trace_include` at `libcpp/line-map.cc:1592@releases/gcc-16.2.0`, which prints when a file +#: is stacked, so a file that is skipped without being opened leaves no line at all. +TRACED = re.compile(r"^(?P\.+) (?P.+)$") + +#: The trailer `-H` prints after everything else, and the only advice GCC gives unasked. +GUARDS_WANTED = "Multiple include guards may be useful for:" + + +@dataclass(frozen=True) +class Include: + depth: int + path: str + + @property + def name(self) -> str: + return self.path.rsplit("/", 1)[-1] + + +@dataclass +class Trace: + """The include tree, as `-H` reports it. + + Every line is one file being opened. A file included twice appears twice, unless the + preprocessor worked out that reading it again could not change anything, in which case + the second `#include` costs nothing and shows nothing. + """ + + text: str + includes: tuple[Include, ...] + guards_wanted: tuple[str, ...] = () + about: str = "" + + def __len__(self) -> int: + return len(self.includes) + + def __iter__(self): + return iter(self.includes) + + @property + def files(self) -> list[str]: + """Distinct paths, in the order first seen.""" + seen: list[str] = [] + for one in self.includes: + if one.path not in seen: + seen.append(one.path) + return seen + + @property + def names(self) -> list[str]: + return [one.name for one in self.includes] + + @property + def depth(self) -> int: + return max((one.depth for one in self.includes), default=0) + + @property + def opened_twice(self) -> list[str]: + """Paths that were stacked more than once, which is the whole header guard story.""" + counts: dict[str, int] = {} + for one in self.includes: + counts[one.path] = counts.get(one.path, 0) + 1 + return sorted(path for path, n in counts.items() if n > 1) + + def under(self, path: str) -> list[Include]: + """Everything included because of `path`, to any depth.""" + found: list[Include] = [] + collecting = False + outer = 0 + for one in self.includes: + if collecting and one.depth <= outer: + collecting = False + if one.path == path and not collecting: + collecting, outer = True, one.depth + continue + if collecting: + found.append(one) + return found + + def tree(self, limit: int = 0) -> str: + shown = self.includes[:limit] if limit else self.includes + return "\n".join(f"{' ' * (one.depth - 1)}{one.name}" for one in shown) + + +def parse_trace(text: str, about: str = "") -> Trace: + """Read `gcc -H` output, which arrives on stderr and is not sorted by anything.""" + includes: list[Include] = [] + wanted: list[str] = [] + trailer = False + for line in text.split("\n"): + if line.startswith(GUARDS_WANTED): + trailer = True + continue + if trailer: + if line.strip(): + wanted.append(line.strip()) + continue + got = TRACED.match(line) + if got: + includes.append(Include(depth=len(got["dots"]), path=got["path"])) + return Trace(text=text, includes=tuple(includes), guards_wanted=tuple(wanted), about=about) + + +# --------------------------------------------------------------------------- +# The pairs that cannot be printed next to each other +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class Pair: + """Two tokens that would lex as one if they were printed with nothing between them. + + `case` is the label in `cpp_avoid_paste` this row stands for, which is what lets a test + check the table against the switch rather than against somebody's memory of it. + """ + + left: str + right: str + case: str + about: str + + @property + def glued(self) -> str: + """What the two would spell with no space, which is the token nobody asked for.""" + return f"{self.left}{self.right}" + + +#: Every pair `cpp_avoid_paste` separates, one row per reason. Not every pair the switch +#: covers, which would be hundreds: one witness per `case` label, chosen so that the glued +#: spelling is a real token a reader recognises. The labels are the checkable part. +PASTES: tuple[Pair, ...] = ( + Pair(">", ">", "CPP_GREATER", "or it would be a right shift"), + Pair("<", "<", "CPP_LESS", "or it would be a left shift"), + Pair("<", ":", "CPP_LESS", "or it would be the digraph for an open bracket"), + Pair("+", "+", "CPP_PLUS", "or it would be an increment"), + Pair("-", "-", "CPP_MINUS", "or it would be a decrement"), + Pair("-", ">", "CPP_MINUS", "or it would be a member access"), + Pair("/", "/", "CPP_DIV", "or it would be a comment, and eat the rest of the line"), + Pair("/", "*", "CPP_DIV", "or it would open a comment that nobody closes"), + Pair("%", ">", "CPP_MOD", "or it would be the digraph for a close brace"), + Pair("&", "&", "CPP_AND", "or it would be a logical and"), + Pair("|", "|", "CPP_OR", "or it would be a logical or"), + Pair(":", ">", "CPP_COLON", "or it would be the digraph for a close bracket"), + Pair("->", "*", "CPP_DEREF", "or it would be a pointer to member, which C++ has"), + Pair(".", ".", "CPP_DOT", "two of three characters of an ellipsis"), + Pair(".", "5", "CPP_DOT", "or it would be the number .5"), + Pair("<=", ">", "CPP_LESS_EQ", "or it would be the spaceship operator"), + Pair("+", "=", "CPP_LAST_EQ", "or it would be a compound assignment"), + Pair("!", "=", "CPP_LAST_EQ", "or it would be a comparison, which is the opposite"), + Pair("x", "y", "CPP_NAME", "or it would be one identifier called xy"), + Pair("x", "5", "CPP_NAME", "or it would be one identifier called x5"), + Pair("L", "'c'", "CPP_NAME", "or it would be a wide character literal"), + Pair("L", '"s"', "CPP_NAME", "or it would be a wide string literal"), + Pair("1", "2", "CPP_NUMBER", "or it would be twelve"), + Pair("1", "x", "CPP_NUMBER", "or it would be a number with a suffix on it"), + Pair("1", ".", "CPP_NUMBER", "or it would be a floating point number"), + Pair("1", "+", "CPP_NUMBER", "or it would be an exponent, in a number like 1e+5"), + Pair("\\", "x", "CPP_OTHER", "or it would be a universal character name"), + Pair("#", "#", "CPP_HASH", "or it would be a paste operator"), + Pair("#", "%", "CPP_HASH", "or it would be the digraph for a paste operator"), +) + +#: Pairs that get nothing, which is half of the demonstration. A rule that fires on every +#: pair is not a rule about tokens, it is a rule about spacing. +KEPT_TOGETHER: tuple[tuple[str, str], ...] = ( + ("+", "-"), + ("x", "+"), + ("*", "&"), + ("]", "["), + (";", ";"), + ("&", "|"), + ("!", "!"), + ("~", "x"), + ("1", "]"), +) + + +@dataclass(frozen=True) +class Probe: + """One pair put next to each other on purpose, and what came out.""" + + left: str + right: str + output: str + case: str = "" + about: str = "" + + @property + def spaced(self) -> bool: + return " " in self.output.strip() + + @property + def glued(self) -> str: + return f"{self.left}{self.right}" + + +# --------------------------------------------------------------------------- +# Expansions +# --------------------------------------------------------------------------- + + +@dataclass(frozen=True) +class Expansion: + """One small file put through `-E`, here and somewhere else. + + `elsewhere` is the same source through an x86-64 Linux GCC of the same release. The + macro tables of two targets have almost nothing in common; the expansion rules have + everything in common, and showing both is cheaper than asserting it. + """ + + name: str + about: str + source: str + output: str + elsewhere: str = "" + + @property + def agrees(self) -> bool: + """Whether the two targets produced the same expansion, ignoring trailing space.""" + if not self.elsewhere: + return True + return _flat(self.output) == _flat(self.elsewhere) + + def pairs(self) -> list[tuple[str, str]]: + """Each line of the program against the line it turned into. + + Directives are dropped, because a `#define` produces no output line to pair with and + pairing around one would put every later line against somebody else's answer. What is + left is one output line per source line, which is what `-P` on these files gives. + """ + was = [line for line in self.source.split("\n") if line.strip() and line[0] != "#"] + now = [line for line in self.output.split("\n") if line.strip()] + if len(was) != len(now): + raise CppError( + f"{self.name} has {len(was)} lines of program and {len(now)} of output," + " so no line can be paired with what it became" + ) + return list(zip(was, now, strict=True)) + + +def _flat(text: str) -> list[str]: + return [line.rstrip() for line in text.split("\n") if line.strip()] + + +def inserted_spaces(source: str, output: str) -> int: + """How many space characters the output has that the source did not. + + A count and not a diff, because the interesting number is that it is not zero. The two + strings are compared with every space removed, so a line that only gained spaces has a + difference of exactly the spaces it gained. + """ + bare = source.replace(" ", "").replace("\t", "") + if output.replace(" ", "").replace("\t", "") != bare: + raise CppError("the output is not the source plus spaces, so counting them says nothing") + return output.count(" ") - source.count(" ") + + +# --------------------------------------------------------------------------- +# The recording +# --------------------------------------------------------------------------- + + +@dataclass +class Builtin: + """What the pinned tree says about macros nobody defined, counted rather than recalled.""" + + array: tuple[str, ...] = () + fixed: tuple[str, ...] = () + + def missing_from(self, table: Macros) -> list[str]: + """Builtins that a dump of every macro does not print, which is nearly all of them.""" + return sorted(name for name in self.array if name not in table) + + +@dataclass +class Recording: + """One run of the F02 recorder.""" + + recorded: str + compiler: str + target: str + tables: dict[str, Macros] + expansions: dict[str, Expansion] + probes: tuple[Probe, ...] + traces: dict[str, Trace] + builtin: Builtin + + #: The four headers the guard experiment was run on, by name. Kept next to the traces + #: rather than written into a lesson, because the whole point of the experiment is that + #: they differ by one line and a reader has to be able to see which line. + headers_source: dict[str, str] = field(default_factory=dict) + + def macros(self, label: str = "local") -> Macros: + if label not in self.tables: + have = ", ".join(sorted(self.tables)) + raise CppError(f"no macro table called {label!r}. There is: {have}") + return self.tables[label] + + def expansion(self, name: str) -> Expansion: + if name not in self.expansions: + have = ", ".join(sorted(self.expansions)) + raise CppError(f"no expansion called {name!r}. There is: {have}") + return self.expansions[name] + + def headers(self, label: str = "local") -> Trace: + if label not in self.traces: + have = ", ".join(sorted(self.traces)) + raise CppError(f"no include trace called {label!r}. There is: {have}") + return self.traces[label] + + def probe(self, left: str, right: str) -> Probe: + for one in self.probes: + if one.left == left and one.right == right: + return one + raise CppError(f"nothing probed {left!r} next to {right!r}") + + @property + def spaced(self) -> list[Probe]: + return [one for one in self.probes if one.spaced] + + @property + def unspaced(self) -> list[Probe]: + return [one for one in self.probes if not one.spaced] + + def __getitem__(self, name: str) -> Expansion: + return self.expansion(name) + + +def load(name: str = "f02", root: Path | str | None = None) -> Recording: + target = Path(root or CORPUS) / f"{name}.json" + if not target.is_file(): + raise CppError(f"{target} is not there. Run lessons/f02-tokens-not-text/record.py.") + raw = json.loads(target.read_text(encoding="utf-8")) + return Recording( + recorded=raw["recorded"], + compiler=raw["compiler"], + target=raw["target"], + tables={ + label: parse_macros( + one["text"], + flags=one.get("flags", ""), + compiler=one["compiler"], + target=one["target"], + about=one["about"], + ) + for label, one in raw["macros"].items() + }, + expansions={ + key: Expansion( + name=key, + about=one["about"], + source=one["source"], + output=one["output"], + elsewhere=one.get("elsewhere", ""), + ) + for key, one in raw["expansions"].items() + }, + probes=tuple( + Probe( + left=one["left"], + right=one["right"], + output=one["output"], + case=one.get("case", ""), + about=one.get("about", ""), + ) + for one in raw["probes"] + ), + traces={ + label: parse_trace(one["text"], about=one["about"]) + for label, one in raw["headers"].items() + }, + builtin=Builtin( + array=tuple(raw["builtin"]["array"]), + fixed=tuple(raw["builtin"]["fixed"]), + ), + headers_source=dict(raw.get("headers_source", {})), + ) + + +__all__ = [ + "CORPUS", + "GUARDS_WANTED", + "KEPT_TOGETHER", + "MARKER_FLAGS", + "PASTES", + "Builtin", + "CppError", + "Expansion", + "Include", + "Macro", + "Macros", + "Marker", + "Pair", + "Probe", + "Recording", + "Trace", + "body", + "inserted_spaces", + "load", + "markers", + "parse_macros", + "parse_trace", +] diff --git a/gxray/glossary.py b/gxray/glossary.py index ec36eb6..f380842 100644 --- a/gxray/glossary.py +++ b/gxray/glossary.py @@ -329,6 +329,76 @@ def anchor(name: str) -> str: ) +PREPROCESSING = Group( + "Before the parser", + "The first program in the chain, and the one whose output every other lesson quietly assumes. F02 is the lesson.", + ( + Term( + name="preprocessor", + short="The phase that runs before the parser, and the only one that works in tokens without types.", + long="It is not a separate program in a normal compilation. `cc1` contains libcpp and calls it for each token, so `gcc -E` is the same code with the output printed instead of parsed. The thing worth unlearning is that it edits text. It lexes your file into tokens, works on tokens, and prints tokens back out, and the printing step has to insert whitespace that was in no input file to stop two of them lexing as one. Everything people find surprising about macros follows from that.", + also=("libcpp", "`cpp`", "`-E`"), + cite="libcpp/init.cc:589@releases/gcc-16.2.0", + see=("token", "translation unit", "cc1"), + met="F02", + ), + Term( + name="token", + short="One lexical unit, with a type, a location and some flags. What the preprocessor deals in.", + long="A `cpp_token` is thirty two bytes on a 64-bit host: a location, a type from a list of about a hundred, a flag word, and a union holding the spelling. `PREV_WHITE` in those flags is the one to know, because it is where the space before a token lives; the space is a property of the token after it rather than a character in a buffer. A macro expanding to nothing can therefore still leave a space behind, and two tokens that arrive next to each other can still be printed apart.", + also=("`cpp_token`", "`PREV_WHITE`"), + cite="libcpp/include/cpplib.h:261@releases/gcc-16.2.0", + see=("preprocessor", "token pasting"), + met="F02", + ), + Term( + name="translation unit", + short="One source file with every #include pasted in and every macro expanded. What the parser sees.", + long="It is the unit C is defined in terms of, and it is much larger than the file you wrote. One `#include ` opens dozens of files, so a hundred line program is routinely tens of thousands of lines by the time the parser starts. This is the reason a compiler feels slow on small files, the reason a macro defined in one header can break a declaration in another, and the reason `gcc -E` is the first thing to run when a build error names a line you cannot find.", + also=("TU",), + see=("preprocessor", "include guard"), + met="F02", + ), + Term( + name="line marker", + short='A `# 42 "file.h" 2 3 4` line in preprocessed output, saying where the following text came from.', + long='Not a comment and not a directive. It is how the preprocessor hands the parser back the line numbers it destroyed by pasting files together, which is what makes an error inside a header point at the header. The digits after the filename are flags: 1 means entering a file, 2 means returning to one, 3 means a system header where warnings are suppressed, and 4 means the contents are to be wrapped in `extern "C"`. Flag 3 is the reason a warning in your code disappears when you move the same code into `/usr/include`.', + also=("`#line`", "linemarker"), + cite="gcc/c-family/c-ppoutput.cc:618@releases/gcc-16.2.0", + see=("preprocessor", "translation unit"), + met="F02", + ), + Term( + name="include guard", + short="The `#ifndef NAME / #define NAME / #endif` wrapper that stops a header being read twice.", + long="The interesting part is not the idiom, it is that libcpp recognises it. When a file's entire token stream is one conditional controlled by a macro, the file is remembered along with that macro's name, and the next `#include` of it is skipped without opening the file at all. The recognition is exact: one declaration after the `#endif` and the optimization is off, though a comment there costs nothing, because the check is over tokens and a comment is not one.", + also=("multiple inclusion guard", "`cmacro`", "`#pragma once`"), + cite="libcpp/files.cc:858@releases/gcc-16.2.0", + see=("preprocessor", "translation unit"), + met="F02", + ), + Term( + name="token pasting", + short="Two things that mean opposite things: the `##` operator, and the accident it is named after.", + long="`a ## b` is the operator, and it makes two tokens into one before the result is scanned for macros, which is why `CAT(PLUS, PLUS)` gives you the identifier `PLUSPLUS` and not `++`. The accident is what `cpp_avoid_paste` exists to prevent: when the preprocessor prints two adjacent tokens that would lex back as one, it puts a space between them that was in no input file. Both are the same fact seen from two sides, which is that the preprocessor's output is tokens and its printed form is a lossy rendering of them.", + also=("`##`", "`cpp_avoid_paste`"), + cite="libcpp/lex.cc:4728@releases/gcc-16.2.0", + see=("token", "preprocessor"), + met="F02", + ), + Term( + name="blue paint", + short="The mark that stops a macro expanding inside its own expansion, so `#define foo foo + 1` terminates.", + long="While a macro is being expanded, its name is disabled; any occurrence of it in the result is flagged `NO_EXPAND` and stays that way forever, even if it is later passed somewhere the macro is not being expanded. The standard's rule and libcpp's implementation are the reason `#define A B` and `#define B A` produce `A` rather than a hang. The name is from a 1980s comp.std.c thread about painting the identifier blue so it cannot be expanded again, and the source uses it.", + also=("`NO_EXPAND`", "painted blue", "self-reference"), + cite="libcpp/macro.cc:1590@releases/gcc-16.2.0", + see=("preprocessor", "token"), + met="F02", + ), + ), +) + + SHAPES = Group( "The four shapes a function takes", "The same function, written down four different ways on its way to assembly. T02, T03 and T07 are the lessons.", @@ -976,6 +1046,7 @@ def anchor(name: str) -> str: READING, FINDING, DRIVING, + PREPROCESSING, SHAPES, CONTROL, STATIC_SINGLE, diff --git a/lessons/CLAIMS.md b/lessons/CLAIMS.md index dd7ee89..98ea2bb 100644 --- a/lessons/CLAIMS.md +++ b/lessons/CLAIMS.md @@ -8,7 +8,7 @@ A few true things cannot be shown from a notebook at all: what a pass does to me Claims about GCC's source rather than its behaviour do not live here. Those carry a `path:line@tag` citation and are checked by `refcheck` against the pinned tree. -150 claims across 18 lessons, 4 of them not observable from a notebook. +165 claims across 19 lessons, 4 of them not observable from a notebook. ## C++ for people who will only ever read it @@ -249,3 +249,23 @@ Claims about GCC's source rather than its behaviour do not live here. Those carr | deleting the !S guard from invoke_as makes gcc -S run the assembler | [`f01-58`](f01-the-spec-language/f01.ipynb) | | a specs file whose name has no star adds a row to the compiler table, teaching gcc a new suffix | [`f01-60`](f01-the-spec-language/f01.ipynb) | | every percent form in both recorded spec tables is one this reader can name | [`f01-66`](f01-the-spec-language/f01.ipynb) | + +## The preprocessor is not a text editor + +| Claim | Proved by | +| --- | --- | +| a C compiler defines hundreds of macros before it reads a line of your program | [`f02-04`](f02-tokens-not-text/f02.ipynb) | +| two builds of one GCC release define different numbers of macros, and neither is wrong | [`f02-08`](f02-tokens-not-text/f02.ipynb) | +| the same C type is a different width on two builds of one compiler release | [`f02-12`](f02-tokens-not-text/f02.ipynb) | +| asking for -std=c23 does not change __STDC_VERSION__, because it was already C23 | [`f02-16`](f02-tokens-not-text/f02.ipynb) | +| almost every macro libcpp builds in is missing from a dump of every macro | [`f02-22`](f02-tokens-not-text/f02.ipynb) | +| preprocessed output can contain a space that is in none of the input files | [`f02-28`](f02-tokens-not-text/f02.ipynb) | +| what gcc printed differs from text substitution by exactly one space character | [`f02-30`](f02-tokens-not-text/f02.ipynb) | +| the pairs that get a space are the pairs that would otherwise lex as one token | [`f02-38`](f02-tokens-not-text/f02.ipynb) | +| every pair the table names came back separated, and nine control pairs came back glued | [`f02-40`](f02-tokens-not-text/f02.ipynb) | +| the paste operator joins tokens before they are rescanned, so its arguments are not expanded | [`f02-44`](f02-tokens-not-text/f02.ipynb) | +| preprocessed output carries the line and file of every piece of text in it | [`f02-56`](f02-tokens-not-text/f02.ipynb) | +| one include of stdio.h opens dozens of files, several levels deep | [`f02-62`](f02-tokens-not-text/f02.ipynb) | +| an include guard is recognised only if the guard is the whole file, in tokens | [`f02-68`](f02-tokens-not-text/f02.ipynb) | +| GCC suggests an include guard only for a file it read exactly once | [`f02-72`](f02-tokens-not-text/f02.ipynb) | +| two targets that share almost no macros expand every one of these files identically | [`f02-76`](f02-tokens-not-text/f02.ipynb) | diff --git a/lessons/f02-tokens-not-text/build.py b/lessons/f02-tokens-not-text/build.py new file mode 100644 index 0000000..a0439f3 --- /dev/null +++ b/lessons/f02-tokens-not-text/build.py @@ -0,0 +1,788 @@ +"""F02. The preprocessor is not a text editor. + +The second lesson of Part II, and the first one about a phase of the compiler proper. F01 +showed the driver deciding which programs to run. This is the first of those programs. + +The lesson has one idea and spends twenty sections earning it: `gcc -E` reads tokens, works +on tokens, and prints tokens, and printing them is lossy. The single most convincing piece of +evidence is a space. `a+EMPTY+b` comes out as `a+ +b`, and there is no input file anywhere +with that space in it. Text substitution cannot produce a character that is in none of its +inputs, so whatever the preprocessor is doing, it is not text substitution. + +Everything runs out of `corpora/cpp/f02.json`: five macro tables, six expansions, thirty +eight probed token pairs and four include traces, half of them recorded on x86-64 Linux +through Compiler Explorer. The source spans are in `corpora/source/f02.json`, so a reader who +cloned shallow and has no `vendor/gcc` sees the same libcpp code as everybody else. + +The reader is expected to have done T01 and F01. This lesson does not re-explain the chain. +""" + +from tools.nbbuild import Lesson + +lesson = Lesson( + "f02-tokens-not-text", + "f02", + title="The preprocessor is not a text editor", + milestone="M3", + summary=( + "That the preprocessor lexes your file into tokens before it does anything else, and " + "that its printed output is a rendering of those tokens rather than the tokens " + "themselves; the space GCC inserts that is in no input file; the four hundred macros " + "you did not write; and why one #include of stdio.h opens thirty eight files" + ), +) +badge = lesson.badge +cite = lesson.cite +term = lesson.term +claim = lesson.claim + + +lesson.md(f""" +# F02. The preprocessor is not a text editor + +{badge} + +Almost everybody carries the same model of the C {term("preprocessor")}: it is a text editor +that runs before the compiler. It pastes headers in, it replaces macro names with their +bodies, and what comes out is a bigger text file. + +That model is wrong in a way you can measure in one line. This lesson measures it, and then +spends the rest of its length on what the right model buys you. + +Here is the measurement, which will not make sense yet and is the whole lesson in three lines. + +```text +#define EMPTY +a+EMPTY+b +``` + +comes out as `a+ +b`. There is a space in that output. There is no space in the input. There +is no space in `EMPTY`, because `EMPTY` is defined to nothing at all. No amount of substituting +text into text produces a character that is in none of the text. + +You need a browser. Everything below runs on a recording, so you see what the lesson saw, on +two targets at once. + +**What you come away with** + +- Knowing that the preprocessor works in {term("token", "tokens")} and that its output is a + rendering of them, not the thing itself +- Being able to read a {term("line marker")}, including the digits after the filename +- Knowing why `#define CAT(a, b) a ## b` cannot make `++` out of two `+` macros +- Knowing what {term("blue paint")} is and why `#define foo foo + 1` does not hang +- Being able to say how many macros your compiler defines before it reads a line, and what + moves that number +- Knowing what an {term("include guard")} has to look like for GCC to skip the file +- Knowing where libcpp is, so the next surprise is a thing you can go and read +""") + +lesson.setup() + +lesson.md(f""" +## The table you did not write + +Start somewhere unarguable. This is a file with one comment in it, compiled with no flags, and +the list of macros that were defined before the compiler read the comment. +{claim("a C compiler defines hundreds of macros before it reads a line of your program")}. +""") + +lesson.code(""" +from gxray import cpp + +rec = cpp.load("f02") +local = rec.macros("local") + +print(f"recorded {rec.recorded}") +print(f"{rec.compiler} for {rec.target}") +print() +print(local) +print(f"{len(local.function_like)} of them take arguments") +print(f"{len(local.empty)} are defined to nothing, which is not the same as not defined") +""") + +lesson.md(""" +Four hundred and forty three. Here are four families of them, with one member of each written +out, so that the range of what is in there is visible. +""") + +lesson.code(""" +for prefix, one in ( + ("__STDC", "__STDC_VERSION__"), + ("__SIZEOF", "__SIZEOF_INT__"), + ("__GCC_ATOMIC", "__GCC_ATOMIC_INT_LOCK_FREE"), + ("__FLT_", "__FLT_MAX__"), +): + names = local.starting(prefix) + print(f"{prefix + '*':<16}{len(names):>3} of them, such as {local[one]}") +""") + +lesson.md(f""" +Those are four different kinds of promise. `__STDC_VERSION__` is the language standard. +`__SIZEOF_INT__` is the machine. `__GCC_ATOMIC_INT_LOCK_FREE` is what the hardware can do +without a library call. `__FLT_MAX__` is a number nobody can write down from memory, which is +the point: `float.h` is mostly a file of `#define FLT_MAX __FLT_MAX__` lines, forwarding to +values the compiler computed. + +## The same release, twice + +The recording has a second table in it, from the same GCC 16.2.0 built for x86-64 Linux by +other people. Not a different version. The same release. +{claim("two builds of one GCC release define different numbers of macros, and neither is wrong")}. +""") + +lesson.code(""" +elsewhere = rec.macros("elsewhere") + +print(f"{local.target:<28}{len(local)} macros") +print(f"{elsewhere.target:<28}{len(elsewhere)} macros") +print() +print(f"{len(local.shared(elsewhere))} names are on both") +print(f"{len(local.only_in(elsewhere))} are only here") +print(f"{len(elsewhere.only_in(local))} are only there") +""") + +lesson.md(""" +The names that exist on one side and not the other are the ones `#ifdef` can see, and they are +the easy half. Here they are. +""") + +lesson.code(""" +for label, names in (("here", local.only_in(elsewhere)), ("there", elsewhere.only_in(local))): + print(f"--- only {label} ({len(names)}) ---") + for start in range(0, min(len(names), 24), 3): + print(" " + "".join(f"{n:<30}" for n in names[start : start + 3]).rstrip()) + print() +""") + +lesson.md(f""" +The hard half is the other set: names that are defined on both, to different values. Those are +invisible to `#ifdef` and visible only to arithmetic, which is where portability bugs live. +{claim("the same C type is a different width on two builds of one compiler release")}. +""") + +lesson.code(""" +differ = local.differing(elsewhere) +print(f"{len(differ)} names are defined on both to different values. Some of them:") +print() +for name in ( + "__SIZEOF_LONG_DOUBLE__", + "__LDBL_MANT_DIG__", + "__INT_FAST16_TYPE__", + "__WINT_TYPE__", + "__USER_LABEL_PREFIX__", +): + print(f" {name:<26}{local[name].body!r:<26}{elsewhere[name].body!r}") +""") + +lesson.md(""" +A `long double` is eight bytes here and sixteen bytes there, with fifty three bits of mantissa +against sixty four. `int_fast16_t` is a `short` here and a `long` there, which is four times +the width. `wint_t` is signed here and unsigned there, so the same comparison against `-1` is +true on one machine and false on the other. And `__USER_LABEL_PREFIX__` is an underscore here +and nothing there, which is why a symbol name in inline assembly is not portable. + +Same C, same standard, same compiler release. Every one of those is a fact about a machine +that got written into a macro before your file was read. + +## What moves the table + +Flags change it, and not the flags a reader expects. Start with the one everybody reaches for. +""") + +lesson.code(""" +optimized = rec.macros("optimized") + +print(f"no flags {len(local)} macros") +print(f"-O2 {len(optimized)} macros") +print() +print("-O2 adds: ", optimized.only_in(local)) +print("-O2 removes:", local.only_in(optimized)) +""") + +lesson.md(f""" +One added and one removed, so the count is identical and the table is not. If you were +comparing two compilers by counting their macros you would have concluded that `-O2` does +nothing, which is a good reminder that a count is not a comparison. + +Now the flag that names a language standard. +{claim("asking for -std=c23 does not change __STDC_VERSION__, because it was already C23")}. +""") + +lesson.code(""" +c23 = rec.macros("c23") + +print("-std=c23 adds: ", c23.only_in(local)) +print("-std=c23 removes:", local.only_in(c23)) +print("-std=c23 changes:", c23.differing(local) or "nothing") +print() +print(f"__STDC_VERSION__ without the flag: {local['__STDC_VERSION__'].body}") +print(f"__STDC_VERSION__ with it: {c23['__STDC_VERSION__'].body}") +""") + +lesson.md(""" +The version number does not move, because GCC 16's default is already C23. What the flag +actually does is add `__STRICT_ANSI__`, which turns the GNU extensions off. `-std=c23` is a +request to stop doing something, and every header on the system reads that macro to decide +whether it is allowed to declare `strdup`. + +Last one, for contrast, because it is the flag that moves the most. +""") + +lesson.code(""" +fast = rec.macros("fast") + +print("-ffast-math adds:", ", ".join(fast.only_in(local))) +print() +for name in fast.differing(local): + print(f" {name:<26}{local[name].body:<8}-> {fast[name].body}") +""") + +lesson.md(""" +`__FAST_MATH__` is how `math.h` finds out. `__GCC_IEC_559` dropping from 2 to 0 is the compiler +writing down, in a macro, that its floating point is no longer IEEE conformant. That is not a +diagnostic and it is not a warning; it is a number in a table that a header can read. + +## The list that is not the list + +Here is a question the table above cannot answer. Where is `__FILE__`? +""") + +lesson.code(""" +print("__FILE__ in the dump of every macro:", "__FILE__" in local) +print("__LINE__ in the dump of every macro:", "__LINE__" in local) +""") + +lesson.md(f""" +Not there. Nor `__LINE__`, nor `__COUNTER__`, nor `__has_include`. `-dM` prints the +preprocessor's hash table, and these are not in it, because they are not macros with bodies. +They are C functions with a name registered in front of them. +{claim("almost every macro libcpp builds in is missing from a dump of every macro")}. +""") + +lesson.code(""" +built = rec.builtin +missing = built.missing_from(local) + +print(f"{len(built.array)} macros have a C function behind them:") +for start in range(0, len(built.array), 4): + print(" " + "".join(f"{n:<22}" for n in built.array[start : start + 4]).rstrip()) +print() +print(f"{len(missing)} of them are missing from -dM output.") +print(f"the one that is not: {[n for n in built.array if n not in missing]}") +""") + +lesson.md(""" +`__STDC__` is the exception, and it is the exception for a boring and satisfying reason: it is +in the array of C functions and it is also defined the ordinary way, with a value, so the hash +table has an entry to print. Every other name on that list would need the compiler to run a +function to answer, and `-dM` has nothing to print. + +Here is the array, in the tree, with the macro that builds each row. +""") + +lesson.code(""" +from gxray import source + +cuts = source.load_extract("f02") +row = cuts["builtins"] + +print(f"{row.span} ({row.citation})") +print(row.about) +print() +print(row.numbered()) +""") + +lesson.md(f""" +`B` is name and function. `C` is a name with an alias, `X` is one that warns when you use it. +The four `__has_*` entries are the ones a reader is most likely to have used this year, and +they are the clearest case: `__has_include()` cannot be a text substitution, because +answering it means searching the include path. + +And the code that decides what `-dM` prints is one loop with one condition in it. +""") + +lesson.code(""" +print(cuts["dump"].numbered()) +""") + +lesson.md(f""" +`cpp_user_macro_p`. A node that is a built-in function is skipped, which is the whole answer. + +## A space that is in no input file + +Now the measurement from the top of the lesson. + +Three lines of C, put through `gcc -E -P`. The `-P` turns the line markers off so that what +comes back is the expansion and nothing else. Read the input, predict the output, then run it. +{claim("preprocessed output can contain a space that is in none of the input files")}. +""") + +lesson.code(""" +spacing = rec.expansion("spacing") + +print(spacing.source) +print("becomes") +print() +for was, now in spacing.pairs(): + print(f" {was:<14}-> {now}") +""") + +lesson.md(f""" +Line one is the one that matters. `a+EMPTY+b` has no space in it. `EMPTY` is defined to +nothing. And the output is `a+ +b`. + +Do the substitution by hand, the way the wrong model says it happens, and compare. +{claim("what gcc printed differs from text substitution by exactly one space character")}. +""") + +lesson.code(""" +was, now = spacing.pairs()[0] +naive = was.replace("EMPTY", "") + +print(f"the input: {was!r}") +print(f"text substitution gives: {naive!r}") +print(f"gcc -E -P gives: {now!r}") +print() +print(f"difference: {cpp.inserted_spaces(naive, now)} space, and nothing else at all") +""") + +lesson.md(""" +If the preprocessor were substituting text, the output would be `a++b`, and `a++b` is a +different program: it is `a++` followed by `b`, which does not parse, and if it did parse it +would increment something. The preprocessor knows that, because it is not holding text. It is +holding a `+` token and another `+` token, and it knows that printing them adjacent would +produce a `++` token, and it will not do that. + +Line two is the same fact from the other side. `a PLUS +b` has one space in the input and two +in the output. Line three, `a+ +b`, already had the space and comes out unchanged, which is +what says the rule is about the tokens and not about the line. + +## The token + +Here is the thing being held. +""") + +lesson.code(""" +print(cuts["token"].numbered()) +""") + +lesson.md(f""" +Thirty two bytes. A source location, a type from a list of about a hundred, a flag word, and +a union with the spelling in it. + +`PREV_WHITE` is the flag to know. Whitespace is not a character in a buffer somewhere: it is a +bit on the token that comes after it. That is why a macro expanding to nothing can leave a +space behind, and why the question "was there a space here" is a thing the preprocessor can +answer at all. + +The type list has one entry in it that surprises people. +""") + +lesson.code(""" +print(cuts["padding"].numbered()) +""") + +lesson.md(f""" +`CPP_PADDING` is a token that is not a token. It is what a macro expansion leaves at its edges +so that the printer can work out the spacing afterwards, and it is why the sentence "an empty +macro expands to nothing" is not quite true. It expands to padding. + +## Which pairs, exactly + +A rule that fires on every pair would be a printer that likes spaces. The interesting question +is which pairs, and the answer is a switch statement. +""") + +lesson.code(""" +print(cuts["avoid-paste"].numbered()) +""") + +lesson.md(f""" +One `case` per left-hand token type, and the body of each says which right-hand tokens are a +problem. `case CPP_DIV: return c == '/' || c == '*';` with the comment `/* Comments. */` is the +one to read twice: two divisions printed together would open a comment and eat the rest of the +line. + +`gxray.cpp` carries at least one witness pair for every one of those labels, and a test +compares the set of labels the table covers against the switch in the pinned tree, so a GCC +that grows a new case fails the build rather than quietly making the next paragraph false. +{claim("the pairs that get a space are the pairs that would otherwise lex as one token")}. +""") + +lesson.code(""" +labels = {one.case for one in cpp.PASTES} +print(f"{len(cpp.PASTES)} witness pairs, covering {len(labels)} of the case labels:") +print() +for one in cpp.PASTES: + print(f" {one.left:>4} {one.right:<6}glued: {one.glued:<8}{one.about}") +""") + +lesson.md(f""" +Each of those was actually run. The file that runs them is thirty eight lines of +`ID(left)ID(right)`, where `ID(x)` is `x`, because wrapping each side in a macro call is the +only way to get two tokens adjacent in a source file with no whitespace character anywhere +between them. +{claim("every pair the table names came back separated, and nine control pairs came back glued")}. +""") + +lesson.code(""" +print(f"{len(rec.probes)} pairs probed") +print(f"{len(rec.spaced)} came out with a space, {len(rec.unspaced)} came out glued") +print() +for one in rec.probes: + mark = "space" if one.spaced else "" + print(f" {one.glued:<8}-> {one.output.strip():<10}{mark:<7}{one.case}") +""") + +lesson.md(""" +The bottom nine are the control. `+-`, `x+`, `*&`, `][`, `;;`, `&|`, `!!`, `~x`, `1]`: every one +of them is two tokens that stay two tokens when printed together, and every one of them came +back untouched. The rule is not a habit of the printer. + +Which is the whole argument, stated as plainly as it can be. The preprocessor inserted a +character into its output, and it chose which pairs to insert it between by asking what the +tokens were. Text does not have types. Tokens do. + +## The printer + +The code that decides is short enough to read. +""") + +lesson.code(""" +print(cuts["spacing"].numbered()) +""") + +lesson.md(f""" +Three reasons for a space, and the comment above the third admits what it is doing: "Subtle. Do +not put a space before a `(` if ...". The first two are the token's own `PREV_WHITE` bit and the +padding left behind by a macro. The third is `cpp_avoid_paste`. + +## The other kind of pasting + +There is exactly one thing in the language that makes two tokens into one, and it is worth +seeing right after the section on the thing that prevents it. +{claim("the paste operator joins tokens before they are rescanned, so its arguments are not expanded")}. +""") + +lesson.code(""" +paste = rec.expansion("paste") + +print(paste.source) +print("becomes") +print() +for was, now in paste.pairs(): + print(f" {was:<20}-> {now}") +""") + +lesson.md(f""" +`CAT(a, b)` gives `ab`, which is what everybody expects. `CAT(PLUS, PLUS)` gives `PLUSPLUS`, +which is not. `PLUS` is a macro defined to `+`, and a text editor would have substituted it and +then joined, giving `++`. + +The rule is that an argument used as an operand of `##` is not macro-expanded first. So `PLUS` +and `PLUS` are joined as they are written, into the single identifier `PLUSPLUS`, which is then +looked up as a macro, is not one, and is printed. This is {term("token pasting")}, and both +halves of the name are now in the lesson: the operator that does it on purpose and the space +that prevents it happening by accident. + +The same rule bites in a more familiar place. +""") + +lesson.code(""" +prescan = rec.expansion("prescan") + +print(prescan.source) +print("becomes") +print() +for was, now in prescan.pairs(): + print(f" {was:<20}-> {now}") +""") + +lesson.md(""" +`STR(PLUS)` gives `"PLUS"`. That is the two-macro dance every C programmer eventually copies out +of somebody else's header without knowing why: `#` also refuses to expand its operand, so you +need an outer macro whose only job is to force the argument through one round of expansion +before the inner one stringifies it. `XSTR(PLUS)` gives `"+"`. + +## Blue paint + +Two more expansions, and then the include path. +{claim("a macro cannot expand inside its own expansion, which is what stops the obvious infinite loop")}. +""") + +lesson.code(""" +paint = rec.expansion("paint") + +print(paint.source) +print("becomes") +print() +for was, now in paint.pairs(): + print(f" {was:<6}-> {now}") +""") + +lesson.md(f""" +`#define foo foo + 1` terminates. So does `#define A B` with `#define B A`, which needs the +same rule applied one level out. + +The mechanism has a name, from a comp.std.c thread in the 1980s: the identifier is painted +blue, and a blue identifier is never expanded again, even if it later turns up somewhere the +macro is not being expanded. In libcpp it is two flags, and here is the first. +""") + +lesson.code(""" +print(cuts["paint"].numbered()) +""") + +lesson.md(f""" +`NODE_DISABLED` while the expansion is in progress, and `NO_EXPAND` stamped onto any token that +came out with the macro's own name on it. The second is the permanent one, and it is why the +result is a property of the token rather than of the moment. + +One more, because it catches people who are sure they know how macros work. +""") + +lesson.code(""" +invocation = rec.expansion("invocation") + +print(invocation.source) +print("becomes") +print() +for was, now in invocation.pairs(): + print(f" {was:<6}-> {now}") +""") + +lesson.md(""" +`f` on its own is not an invocation of `f`, so it is left alone. A function-like macro expands +only when the next token is an open bracket, which is what lets a header define a macro with the +same name as a function and still let you take the function's address. `f (2)` with a space +does expand, because the rule is about the next token and a space is not one. + +## Where the text actually comes from + +Turn the line markers back on. Everything so far used `-P`, which suppresses them. Here is the +same kind of file without it. +""") + +lesson.code(""" +markers = rec.expansion("markers") + +print(markers.source) +print("becomes") +print() +print(markers.output) +""") + +lesson.md(f""" +Those `#` lines are {term("line marker", "line markers")}. They are not comments, they are not +directives, and they are the mechanism by which an error inside a header points at the header: +the preprocessor destroyed the line numbering by pasting files together, and these hand it +back. +{claim("preprocessed output carries the line and file of every piece of text in it")}. +""") + +lesson.code(""" +for one in cpp.markers(markers.output): + print(f" {one}") +""") + +lesson.md(f""" +The digits after the filename are flags, and knowing them turns a wall of noise into four +facts. GCC documents them in exactly one place in the tree. +""") + +lesson.code(""" +print(cuts["marker-flags"].numbered()) +""") + +lesson.md(f""" +Flag 3 is the one worth carrying around. A file marked as a system header has its warnings +suppressed, which is why moving a piece of code into `/usr/include` silences a warning about it, +and why `-Wsystem-headers` exists. + +The code that prints the line is eleven lines. +""") + +lesson.code(""" +print(cuts["markers"].numbered()) +""") + +lesson.md(f""" +The 1 and the 2 come in as `special_flags`, a string the caller passes. The 3 and the 4 are +worked out here from `in_system_header_at`. Which is a small thing, and it explains why a marker +can say `1 3 4` but never `4 1`: the two halves are printed by different code. + +## Thirty eight files + +One `#include `. `-H` prints every file that gets opened, one dot per level. +{claim("one include of stdio.h opens dozens of files, several levels deep")}. +""") + +lesson.code(""" +here = rec.headers("local") + +print(here.about) +print(f"{len(here)} files opened, {len(here.files)} of them distinct, {here.depth} levels deep") +print() +print(here.tree(18)) +print(" ...") +""") + +lesson.md(f""" +That is what a {term("translation unit")} is. Not the file you wrote: the file you wrote with +everything it dragged in, which for a program whose body is one `puts` call is thirty eight +files and some tens of thousands of lines. + +The same two lines somewhere else. +""") + +lesson.code(""" +there = rec.headers("elsewhere") + +print(f"{local.target:<28}{len(here.files):>4} distinct files") +print(f"{elsewhere.target:<28}{len(there.files):>4} distinct files") +print() +print(there.tree(12)) +print(" ...") +print() +print("files in common:", set(here.files) & set(there.files) or "none at all") +""") + +lesson.md(""" +Not one file in common. Same standard header, same release, same two lines of C, and the two +trees share nothing, because one of them is an Apple SDK and the other is glibc. Every +portability question about headers is downstream of that picture. + +## Reading a header twice + +The second `#include ` in that file cost nothing, and it is worth knowing exactly what +"nothing" means. Four headers, differing by one line each, included twice apiece. +""") + +lesson.code(""" +for name, text in sorted(rec.headers_source.items()): + print(f"--- {name}") + for line in text.rstrip().split(chr(10)): + print(f" {line}") +""") + +lesson.md(f""" +`clean.h` is the ordinary idiom. `untidy.h` has a comment after the `#endif`. `stray.h` has one +declaration after the `#endif`. `bare.h` has no guard at all. Predict which ones get opened +twice before running the next cell. +{claim("an include guard is recognised only if the guard is the whole file, in tokens")}. +""") + +lesson.code(""" +guards = rec.headers("guards") + +print(guards.text) +print(f"opened twice: {', '.join(guards.opened_twice)}") +""") + +lesson.md(f""" +`untidy.h` was read once, and `stray.h` was read twice. The difference between them is a +comment and a declaration in the same position, which is the difference between something that +is a token and something that is not. The optimization needs the file's entire token stream to +be one conditional, and comments are gone before anything counts tokens. + +The condition itself is two lines. +""") + +lesson.code(""" +print(cuts["guard"].numbered()) +""") + +lesson.md(f""" +`file->cmacro` is the name of the guard macro, remembered from the first read. If it is still +defined, the file is not opened. Note what that means for `#pragma once`: it is a different +mechanism with the same effect, and GCC supports both, but the guard version is the one that +works when the same header arrives through two different paths with two different `stat` +results. + +`-H` will also volunteer advice about this, and the advice has a condition on it that catches +everybody. +{claim("GCC suggests an include guard only for a file it read exactly once")}. +""") + +lesson.code(""" +once = rec.headers("once") + +print("--- each header included twice") +print(f" suggestions: {list(guards.guards_wanted) or 'none'}") +print() +print("--- each header included once") +print(f" suggestions: {[p.rsplit('/', 1)[-1] for p in once.guards_wanted]}") +""") + +lesson.md(f""" +The run where two headers were read twice suggested nothing. The run where every header was +read once named the two that have no usable guard. + +That is not a bug, and the reason is one line of the condition. +""") + +lesson.code(""" +print(cuts["advice"].numbered()) +""") + +lesson.md(f""" +`file->stack_count == 1`. GCC only advises about files it read exactly once, on the theory that +a file it read twice has already cost you the time and does not need a hint. Which means the +suggestion arrives for the header you have not yet had trouble with, and never for the one you +have. Worth knowing before you go looking for it in a build that is slow because of exactly +this problem. + +## Two targets, one set of rules + +One last comparison, and it is the one that says where the line is. The macro tables of these +two compilers share almost nothing. Every expansion above was recorded on both, and the +question is whether any of them came out differently. +{claim("two targets that share almost no macros expand every one of these files identically")}. +""") + +lesson.code(""" +for name in ("spacing", "prescan", "paste", "paint", "invocation"): + one = rec.expansion(name) + print(f"{name:<12}{'same' if one.agrees else 'DIFFERENT'} {one.about}") +""") + +lesson.md(""" +Identical, all of them. Which is the shape of the whole subject: the vocabulary is the target's +and the grammar is the language's. `__SIZEOF_LONG_DOUBLE__` is a fact about a machine. +`a+EMPTY+b` becoming `a+ +b` is a fact about C, and it will be the same on a compiler for a +processor that does not exist yet. + +## Boss fight + +No new tools. Three questions, answerable from the recording: + +1. Thirty eight pairs of tokens were put next to each other with no whitespace between them. + How many came out of the preprocessor with a space in? +2. Four headers were each included twice. Which of them were actually opened twice? +3. Twenty macros are built into libcpp with a C function behind them, and a dump of every + macro prints exactly one of them. Which one, and why that one? + +Then check yourself: + +```text +python lessons/f02-tokens-not-text/grade.py +``` + +or, from a checkout, `just grade f02-tokens-not-text`. It takes answers on the command line +too, so `--spaces 29 --twice a.h,b.h --odd SOME_MACRO` is a whole submission. Every answer it +marks against is worked out from the recording rather than written down. + +## What to read next + +F03 is the C parser, which is the program that reads the tokens this lesson has been printing. +The handover between them is one function call, and knowing that the parser never sees a +character of your file explains a great deal about GCC's error messages. + +F01 is the lesson before this one, if you have not done it. It shows how `cc1` gets run at all. + +If you have a GCC on your machine, every measurement here is one command. `gcc -dM -E - ' | gcc -H -E - >/dev/null` +is your include tree, and it will not match this one. That is the lesson. +""") + +raise SystemExit(lesson.save()) diff --git a/lessons/f02-tokens-not-text/f02.ipynb b/lessons/f02-tokens-not-text/f02.ipynb new file mode 100644 index 0000000..87b76d1 --- /dev/null +++ b/lessons/f02-tokens-not-text/f02.ipynb @@ -0,0 +1,1176 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f02-01", + "metadata": {}, + "source": [ + "# F02. The preprocessor is not a text editor\n", + "\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/gcc-internals/blob/main/lessons/f02-tokens-not-text/f02.ipynb)\n", + "\n", + "Almost everybody carries the same model of the C [preprocessor](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#preprocessor): it is a text editor\n", + "that runs before the compiler. It pastes headers in, it replaces macro names with their\n", + "bodies, and what comes out is a bigger text file.\n", + "\n", + "That model is wrong in a way you can measure in one line. This lesson measures it, and then\n", + "spends the rest of its length on what the right model buys you.\n", + "\n", + "Here is the measurement, which will not make sense yet and is the whole lesson in three lines.\n", + "\n", + "```text\n", + "#define EMPTY\n", + "a+EMPTY+b\n", + "```\n", + "\n", + "comes out as `a+ +b`. There is a space in that output. There is no space in the input. There\n", + "is no space in `EMPTY`, because `EMPTY` is defined to nothing at all. No amount of substituting\n", + "text into text produces a character that is in none of the text.\n", + "\n", + "You need a browser. Everything below runs on a recording, so you see what the lesson saw, on\n", + "two targets at once.\n", + "\n", + "**What you come away with**\n", + "\n", + "- Knowing that the preprocessor works in [tokens](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#token) and that its output is a\n", + " rendering of them, not the thing itself\n", + "- Being able to read a [line marker](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#line-marker), including the digits after the filename\n", + "- Knowing why `#define CAT(a, b) a ## b` cannot make `++` out of two `+` macros\n", + "- Knowing what [blue paint](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#blue-paint) is and why `#define foo foo + 1` does not hang\n", + "- Being able to say how many macros your compiler defines before it reads a line, and what\n", + " moves that number\n", + "- Knowing what an [include guard](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#include-guard) has to look like for GCC to skip the file\n", + "- Knowing where libcpp is, so the next surprise is a thing you can go and read" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-02", + "metadata": {}, + "outputs": [], + "source": [ + "# Setup. Safe to run twice, and does nothing at all if you already have the repository.\n", + "#\n", + "# Colab starts with none of this project's files and a GCC that is several years older than\n", + "# the one the lessons were written against. This cell fixes the first problem by cloning,\n", + "# and works around the second by having gxray fall back to recorded dumps or to Compiler\n", + "# Explorer, both of which are really GCC 16.\n", + "import os\n", + "import subprocess\n", + "import sys\n", + "\n", + "REPO = \"https://github.com/tamnd/gcc-internals\"\n", + "\n", + "if \"google.colab\" in sys.modules:\n", + " if not os.path.isdir(\"gcc-internals\"):\n", + " subprocess.run([\"git\", \"clone\", \"--depth\", \"1\", \"-q\", REPO], check=True)\n", + " if os.path.basename(os.getcwd()) != \"gcc-internals\":\n", + " os.chdir(\"gcc-internals\")\n", + " if os.getcwd() not in sys.path:\n", + " sys.path.insert(0, os.getcwd())\n", + "\n", + "import gxray\n", + "\n", + "print(\"gxray\", gxray.__version__, \"on python\", sys.version.split()[0])" + ] + }, + { + "cell_type": "markdown", + "id": "f02-03", + "metadata": {}, + "source": [ + "## The table you did not write\n", + "\n", + "Start somewhere unarguable. This is a file with one comment in it, compiled with no flags, and\n", + "the list of macros that were defined before the compiler read the comment.\n", + "a C compiler defines hundreds of macros before it reads a line of your program." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-04", + "metadata": {}, + "outputs": [], + "source": [ + "from gxray import cpp\n", + "\n", + "rec = cpp.load(\"f02\")\n", + "local = rec.macros(\"local\")\n", + "\n", + "print(f\"recorded {rec.recorded}\")\n", + "print(f\"{rec.compiler} for {rec.target}\")\n", + "print()\n", + "print(local)\n", + "print(f\"{len(local.function_like)} of them take arguments\")\n", + "print(f\"{len(local.empty)} are defined to nothing, which is not the same as not defined\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-05", + "metadata": {}, + "source": [ + "Four hundred and forty three. Here are four families of them, with one member of each written\n", + "out, so that the range of what is in there is visible." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-06", + "metadata": {}, + "outputs": [], + "source": [ + "for prefix, one in (\n", + " (\"__STDC\", \"__STDC_VERSION__\"),\n", + " (\"__SIZEOF\", \"__SIZEOF_INT__\"),\n", + " (\"__GCC_ATOMIC\", \"__GCC_ATOMIC_INT_LOCK_FREE\"),\n", + " (\"__FLT_\", \"__FLT_MAX__\"),\n", + "):\n", + " names = local.starting(prefix)\n", + " print(f\"{prefix + '*':<16}{len(names):>3} of them, such as {local[one]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-07", + "metadata": {}, + "source": [ + "Those are four different kinds of promise. `__STDC_VERSION__` is the language standard.\n", + "`__SIZEOF_INT__` is the machine. `__GCC_ATOMIC_INT_LOCK_FREE` is what the hardware can do\n", + "without a library call. `__FLT_MAX__` is a number nobody can write down from memory, which is\n", + "the point: `float.h` is mostly a file of `#define FLT_MAX __FLT_MAX__` lines, forwarding to\n", + "values the compiler computed.\n", + "\n", + "## The same release, twice\n", + "\n", + "The recording has a second table in it, from the same GCC 16.2.0 built for x86-64 Linux by\n", + "other people. Not a different version. The same release.\n", + "two builds of one GCC release define different numbers of macros, and neither is wrong." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-08", + "metadata": {}, + "outputs": [], + "source": [ + "elsewhere = rec.macros(\"elsewhere\")\n", + "\n", + "print(f\"{local.target:<28}{len(local)} macros\")\n", + "print(f\"{elsewhere.target:<28}{len(elsewhere)} macros\")\n", + "print()\n", + "print(f\"{len(local.shared(elsewhere))} names are on both\")\n", + "print(f\"{len(local.only_in(elsewhere))} are only here\")\n", + "print(f\"{len(elsewhere.only_in(local))} are only there\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-09", + "metadata": {}, + "source": [ + "The names that exist on one side and not the other are the ones `#ifdef` can see, and they are\n", + "the easy half. Here they are." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-10", + "metadata": {}, + "outputs": [], + "source": [ + "for label, names in ((\"here\", local.only_in(elsewhere)), (\"there\", elsewhere.only_in(local))):\n", + " print(f\"--- only {label} ({len(names)}) ---\")\n", + " for start in range(0, min(len(names), 24), 3):\n", + " print(\" \" + \"\".join(f\"{n:<30}\" for n in names[start : start + 3]).rstrip())\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "id": "f02-11", + "metadata": {}, + "source": [ + "The hard half is the other set: names that are defined on both, to different values. Those are\n", + "invisible to `#ifdef` and visible only to arithmetic, which is where portability bugs live.\n", + "the same C type is a different width on two builds of one compiler release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-12", + "metadata": {}, + "outputs": [], + "source": [ + "differ = local.differing(elsewhere)\n", + "print(f\"{len(differ)} names are defined on both to different values. Some of them:\")\n", + "print()\n", + "for name in (\n", + " \"__SIZEOF_LONG_DOUBLE__\",\n", + " \"__LDBL_MANT_DIG__\",\n", + " \"__INT_FAST16_TYPE__\",\n", + " \"__WINT_TYPE__\",\n", + " \"__USER_LABEL_PREFIX__\",\n", + "):\n", + " print(f\" {name:<26}{local[name].body!r:<26}{elsewhere[name].body!r}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-13", + "metadata": {}, + "source": [ + "A `long double` is eight bytes here and sixteen bytes there, with fifty three bits of mantissa\n", + "against sixty four. `int_fast16_t` is a `short` here and a `long` there, which is four times\n", + "the width. `wint_t` is signed here and unsigned there, so the same comparison against `-1` is\n", + "true on one machine and false on the other. And `__USER_LABEL_PREFIX__` is an underscore here\n", + "and nothing there, which is why a symbol name in inline assembly is not portable.\n", + "\n", + "Same C, same standard, same compiler release. Every one of those is a fact about a machine\n", + "that got written into a macro before your file was read.\n", + "\n", + "## What moves the table\n", + "\n", + "Flags change it, and not the flags a reader expects. Start with the one everybody reaches for." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-14", + "metadata": {}, + "outputs": [], + "source": [ + "optimized = rec.macros(\"optimized\")\n", + "\n", + "print(f\"no flags {len(local)} macros\")\n", + "print(f\"-O2 {len(optimized)} macros\")\n", + "print()\n", + "print(\"-O2 adds: \", optimized.only_in(local))\n", + "print(\"-O2 removes:\", local.only_in(optimized))" + ] + }, + { + "cell_type": "markdown", + "id": "f02-15", + "metadata": {}, + "source": [ + "One added and one removed, so the count is identical and the table is not. If you were\n", + "comparing two compilers by counting their macros you would have concluded that `-O2` does\n", + "nothing, which is a good reminder that a count is not a comparison.\n", + "\n", + "Now the flag that names a language standard.\n", + "asking for -std=c23 does not change __STDC_VERSION__, because it was already C23." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-16", + "metadata": {}, + "outputs": [], + "source": [ + "c23 = rec.macros(\"c23\")\n", + "\n", + "print(\"-std=c23 adds: \", c23.only_in(local))\n", + "print(\"-std=c23 removes:\", local.only_in(c23))\n", + "print(\"-std=c23 changes:\", c23.differing(local) or \"nothing\")\n", + "print()\n", + "print(f\"__STDC_VERSION__ without the flag: {local['__STDC_VERSION__'].body}\")\n", + "print(f\"__STDC_VERSION__ with it: {c23['__STDC_VERSION__'].body}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-17", + "metadata": {}, + "source": [ + "The version number does not move, because GCC 16's default is already C23. What the flag\n", + "actually does is add `__STRICT_ANSI__`, which turns the GNU extensions off. `-std=c23` is a\n", + "request to stop doing something, and every header on the system reads that macro to decide\n", + "whether it is allowed to declare `strdup`.\n", + "\n", + "Last one, for contrast, because it is the flag that moves the most." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-18", + "metadata": {}, + "outputs": [], + "source": [ + "fast = rec.macros(\"fast\")\n", + "\n", + "print(\"-ffast-math adds:\", \", \".join(fast.only_in(local)))\n", + "print()\n", + "for name in fast.differing(local):\n", + " print(f\" {name:<26}{local[name].body:<8}-> {fast[name].body}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-19", + "metadata": {}, + "source": [ + "`__FAST_MATH__` is how `math.h` finds out. `__GCC_IEC_559` dropping from 2 to 0 is the compiler\n", + "writing down, in a macro, that its floating point is no longer IEEE conformant. That is not a\n", + "diagnostic and it is not a warning; it is a number in a table that a header can read.\n", + "\n", + "## The list that is not the list\n", + "\n", + "Here is a question the table above cannot answer. Where is `__FILE__`?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-20", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"__FILE__ in the dump of every macro:\", \"__FILE__\" in local)\n", + "print(\"__LINE__ in the dump of every macro:\", \"__LINE__\" in local)" + ] + }, + { + "cell_type": "markdown", + "id": "f02-21", + "metadata": {}, + "source": [ + "Not there. Nor `__LINE__`, nor `__COUNTER__`, nor `__has_include`. `-dM` prints the\n", + "preprocessor's hash table, and these are not in it, because they are not macros with bodies.\n", + "They are C functions with a name registered in front of them.\n", + "almost every macro libcpp builds in is missing from a dump of every macro." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-22", + "metadata": {}, + "outputs": [], + "source": [ + "built = rec.builtin\n", + "missing = built.missing_from(local)\n", + "\n", + "print(f\"{len(built.array)} macros have a C function behind them:\")\n", + "for start in range(0, len(built.array), 4):\n", + " print(\" \" + \"\".join(f\"{n:<22}\" for n in built.array[start : start + 4]).rstrip())\n", + "print()\n", + "print(f\"{len(missing)} of them are missing from -dM output.\")\n", + "print(f\"the one that is not: {[n for n in built.array if n not in missing]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-23", + "metadata": {}, + "source": [ + "`__STDC__` is the exception, and it is the exception for a boring and satisfying reason: it is\n", + "in the array of C functions and it is also defined the ordinary way, with a value, so the hash\n", + "table has an entry to print. Every other name on that list would need the compiler to run a\n", + "function to answer, and `-dM` has nothing to print.\n", + "\n", + "Here is the array, in the tree, with the macro that builds each row." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-24", + "metadata": {}, + "outputs": [], + "source": [ + "from gxray import source\n", + "\n", + "cuts = source.load_extract(\"f02\")\n", + "row = cuts[\"builtins\"]\n", + "\n", + "print(f\"{row.span} ({row.citation})\")\n", + "print(row.about)\n", + "print()\n", + "print(row.numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-25", + "metadata": {}, + "source": [ + "`B` is name and function. `C` is a name with an alias, `X` is one that warns when you use it.\n", + "The four `__has_*` entries are the ones a reader is most likely to have used this year, and\n", + "they are the clearest case: `__has_include()` cannot be a text substitution, because\n", + "answering it means searching the include path.\n", + "\n", + "And the code that decides what `-dM` prints is one loop with one condition in it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-26", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"dump\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-27", + "metadata": {}, + "source": [ + "`cpp_user_macro_p`. A node that is a built-in function is skipped, which is the whole answer.\n", + "\n", + "## A space that is in no input file\n", + "\n", + "Now the measurement from the top of the lesson.\n", + "\n", + "Three lines of C, put through `gcc -E -P`. The `-P` turns the line markers off so that what\n", + "comes back is the expansion and nothing else. Read the input, predict the output, then run it.\n", + "preprocessed output can contain a space that is in none of the input files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-28", + "metadata": {}, + "outputs": [], + "source": [ + "spacing = rec.expansion(\"spacing\")\n", + "\n", + "print(spacing.source)\n", + "print(\"becomes\")\n", + "print()\n", + "for was, now in spacing.pairs():\n", + " print(f\" {was:<14}-> {now}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-29", + "metadata": {}, + "source": [ + "Line one is the one that matters. `a+EMPTY+b` has no space in it. `EMPTY` is defined to\n", + "nothing. And the output is `a+ +b`.\n", + "\n", + "Do the substitution by hand, the way the wrong model says it happens, and compare.\n", + "what gcc printed differs from text substitution by exactly one space character." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-30", + "metadata": {}, + "outputs": [], + "source": [ + "was, now = spacing.pairs()[0]\n", + "naive = was.replace(\"EMPTY\", \"\")\n", + "\n", + "print(f\"the input: {was!r}\")\n", + "print(f\"text substitution gives: {naive!r}\")\n", + "print(f\"gcc -E -P gives: {now!r}\")\n", + "print()\n", + "print(f\"difference: {cpp.inserted_spaces(naive, now)} space, and nothing else at all\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-31", + "metadata": {}, + "source": [ + "If the preprocessor were substituting text, the output would be `a++b`, and `a++b` is a\n", + "different program: it is `a++` followed by `b`, which does not parse, and if it did parse it\n", + "would increment something. The preprocessor knows that, because it is not holding text. It is\n", + "holding a `+` token and another `+` token, and it knows that printing them adjacent would\n", + "produce a `++` token, and it will not do that.\n", + "\n", + "Line two is the same fact from the other side. `a PLUS +b` has one space in the input and two\n", + "in the output. Line three, `a+ +b`, already had the space and comes out unchanged, which is\n", + "what says the rule is about the tokens and not about the line.\n", + "\n", + "## The token\n", + "\n", + "Here is the thing being held." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-32", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"token\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-33", + "metadata": {}, + "source": [ + "Thirty two bytes. A source location, a type from a list of about a hundred, a flag word, and\n", + "a union with the spelling in it.\n", + "\n", + "`PREV_WHITE` is the flag to know. Whitespace is not a character in a buffer somewhere: it is a\n", + "bit on the token that comes after it. That is why a macro expanding to nothing can leave a\n", + "space behind, and why the question \"was there a space here\" is a thing the preprocessor can\n", + "answer at all.\n", + "\n", + "The type list has one entry in it that surprises people." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-34", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"padding\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-35", + "metadata": {}, + "source": [ + "`CPP_PADDING` is a token that is not a token. It is what a macro expansion leaves at its edges\n", + "so that the printer can work out the spacing afterwards, and it is why the sentence \"an empty\n", + "macro expands to nothing\" is not quite true. It expands to padding.\n", + "\n", + "## Which pairs, exactly\n", + "\n", + "A rule that fires on every pair would be a printer that likes spaces. The interesting question\n", + "is which pairs, and the answer is a switch statement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-36", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"avoid-paste\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-37", + "metadata": {}, + "source": [ + "One `case` per left-hand token type, and the body of each says which right-hand tokens are a\n", + "problem. `case CPP_DIV: return c == '/' || c == '*';` with the comment `/* Comments. */` is the\n", + "one to read twice: two divisions printed together would open a comment and eat the rest of the\n", + "line.\n", + "\n", + "`gxray.cpp` carries at least one witness pair for every one of those labels, and a test\n", + "compares the set of labels the table covers against the switch in the pinned tree, so a GCC\n", + "that grows a new case fails the build rather than quietly making the next paragraph false.\n", + "the pairs that get a space are the pairs that would otherwise lex as one token." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-38", + "metadata": {}, + "outputs": [], + "source": [ + "labels = {one.case for one in cpp.PASTES}\n", + "print(f\"{len(cpp.PASTES)} witness pairs, covering {len(labels)} of the case labels:\")\n", + "print()\n", + "for one in cpp.PASTES:\n", + " print(f\" {one.left:>4} {one.right:<6}glued: {one.glued:<8}{one.about}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-39", + "metadata": {}, + "source": [ + "Each of those was actually run. The file that runs them is thirty eight lines of\n", + "`ID(left)ID(right)`, where `ID(x)` is `x`, because wrapping each side in a macro call is the\n", + "only way to get two tokens adjacent in a source file with no whitespace character anywhere\n", + "between them.\n", + "every pair the table names came back separated, and nine control pairs came back glued." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-40", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"{len(rec.probes)} pairs probed\")\n", + "print(f\"{len(rec.spaced)} came out with a space, {len(rec.unspaced)} came out glued\")\n", + "print()\n", + "for one in rec.probes:\n", + " mark = \"space\" if one.spaced else \"\"\n", + " print(f\" {one.glued:<8}-> {one.output.strip():<10}{mark:<7}{one.case}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-41", + "metadata": {}, + "source": [ + "The bottom nine are the control. `+-`, `x+`, `*&`, `][`, `;;`, `&|`, `!!`, `~x`, `1]`: every one\n", + "of them is two tokens that stay two tokens when printed together, and every one of them came\n", + "back untouched. The rule is not a habit of the printer.\n", + "\n", + "Which is the whole argument, stated as plainly as it can be. The preprocessor inserted a\n", + "character into its output, and it chose which pairs to insert it between by asking what the\n", + "tokens were. Text does not have types. Tokens do.\n", + "\n", + "## The printer\n", + "\n", + "The code that decides is short enough to read." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-42", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"spacing\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-43", + "metadata": {}, + "source": [ + "Three reasons for a space, and the comment above the third admits what it is doing: \"Subtle. Do\n", + "not put a space before a `(` if ...\". The first two are the token's own `PREV_WHITE` bit and the\n", + "padding left behind by a macro. The third is `cpp_avoid_paste`.\n", + "\n", + "## The other kind of pasting\n", + "\n", + "There is exactly one thing in the language that makes two tokens into one, and it is worth\n", + "seeing right after the section on the thing that prevents it.\n", + "the paste operator joins tokens before they are rescanned, so its arguments are not expanded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-44", + "metadata": {}, + "outputs": [], + "source": [ + "paste = rec.expansion(\"paste\")\n", + "\n", + "print(paste.source)\n", + "print(\"becomes\")\n", + "print()\n", + "for was, now in paste.pairs():\n", + " print(f\" {was:<20}-> {now}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-45", + "metadata": {}, + "source": [ + "`CAT(a, b)` gives `ab`, which is what everybody expects. `CAT(PLUS, PLUS)` gives `PLUSPLUS`,\n", + "which is not. `PLUS` is a macro defined to `+`, and a text editor would have substituted it and\n", + "then joined, giving `++`.\n", + "\n", + "The rule is that an argument used as an operand of `##` is not macro-expanded first. So `PLUS`\n", + "and `PLUS` are joined as they are written, into the single identifier `PLUSPLUS`, which is then\n", + "looked up as a macro, is not one, and is printed. This is [token pasting](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#token-pasting), and both\n", + "halves of the name are now in the lesson: the operator that does it on purpose and the space\n", + "that prevents it happening by accident.\n", + "\n", + "The same rule bites in a more familiar place." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-46", + "metadata": {}, + "outputs": [], + "source": [ + "prescan = rec.expansion(\"prescan\")\n", + "\n", + "print(prescan.source)\n", + "print(\"becomes\")\n", + "print()\n", + "for was, now in prescan.pairs():\n", + " print(f\" {was:<20}-> {now}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-47", + "metadata": {}, + "source": [ + "`STR(PLUS)` gives `\"PLUS\"`. That is the two-macro dance every C programmer eventually copies out\n", + "of somebody else's header without knowing why: `#` also refuses to expand its operand, so you\n", + "need an outer macro whose only job is to force the argument through one round of expansion\n", + "before the inner one stringifies it. `XSTR(PLUS)` gives `\"+\"`.\n", + "\n", + "## Blue paint\n", + "\n", + "Two more expansions, and then the include path.\n", + "{claim(\"a macro cannot expand inside its own expansion, which is what stops the obvious infinite loop\")}." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-48", + "metadata": {}, + "outputs": [], + "source": [ + "paint = rec.expansion(\"paint\")\n", + "\n", + "print(paint.source)\n", + "print(\"becomes\")\n", + "print()\n", + "for was, now in paint.pairs():\n", + " print(f\" {was:<6}-> {now}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-49", + "metadata": {}, + "source": [ + "`#define foo foo + 1` terminates. So does `#define A B` with `#define B A`, which needs the\n", + "same rule applied one level out.\n", + "\n", + "The mechanism has a name, from a comp.std.c thread in the 1980s: the identifier is painted\n", + "blue, and a blue identifier is never expanded again, even if it later turns up somewhere the\n", + "macro is not being expanded. In libcpp it is two flags, and here is the first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-50", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"paint\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-51", + "metadata": {}, + "source": [ + "`NODE_DISABLED` while the expansion is in progress, and `NO_EXPAND` stamped onto any token that\n", + "came out with the macro's own name on it. The second is the permanent one, and it is why the\n", + "result is a property of the token rather than of the moment.\n", + "\n", + "One more, because it catches people who are sure they know how macros work." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-52", + "metadata": {}, + "outputs": [], + "source": [ + "invocation = rec.expansion(\"invocation\")\n", + "\n", + "print(invocation.source)\n", + "print(\"becomes\")\n", + "print()\n", + "for was, now in invocation.pairs():\n", + " print(f\" {was:<6}-> {now}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-53", + "metadata": {}, + "source": [ + "`f` on its own is not an invocation of `f`, so it is left alone. A function-like macro expands\n", + "only when the next token is an open bracket, which is what lets a header define a macro with the\n", + "same name as a function and still let you take the function's address. `f (2)` with a space\n", + "does expand, because the rule is about the next token and a space is not one.\n", + "\n", + "## Where the text actually comes from\n", + "\n", + "Turn the line markers back on. Everything so far used `-P`, which suppresses them. Here is the\n", + "same kind of file without it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-54", + "metadata": {}, + "outputs": [], + "source": [ + "markers = rec.expansion(\"markers\")\n", + "\n", + "print(markers.source)\n", + "print(\"becomes\")\n", + "print()\n", + "print(markers.output)" + ] + }, + { + "cell_type": "markdown", + "id": "f02-55", + "metadata": {}, + "source": [ + "Those `#` lines are [line markers](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#line-marker). They are not comments, they are not\n", + "directives, and they are the mechanism by which an error inside a header points at the header:\n", + "the preprocessor destroyed the line numbering by pasting files together, and these hand it\n", + "back.\n", + "preprocessed output carries the line and file of every piece of text in it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-56", + "metadata": {}, + "outputs": [], + "source": [ + "for one in cpp.markers(markers.output):\n", + " print(f\" {one}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-57", + "metadata": {}, + "source": [ + "The digits after the filename are flags, and knowing them turns a wall of noise into four\n", + "facts. GCC documents them in exactly one place in the tree." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-58", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"marker-flags\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-59", + "metadata": {}, + "source": [ + "Flag 3 is the one worth carrying around. A file marked as a system header has its warnings\n", + "suppressed, which is why moving a piece of code into `/usr/include` silences a warning about it,\n", + "and why `-Wsystem-headers` exists.\n", + "\n", + "The code that prints the line is eleven lines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-60", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"markers\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-61", + "metadata": {}, + "source": [ + "The 1 and the 2 come in as `special_flags`, a string the caller passes. The 3 and the 4 are\n", + "worked out here from `in_system_header_at`. Which is a small thing, and it explains why a marker\n", + "can say `1 3 4` but never `4 1`: the two halves are printed by different code.\n", + "\n", + "## Thirty eight files\n", + "\n", + "One `#include `. `-H` prints every file that gets opened, one dot per level.\n", + "one include of stdio.h opens dozens of files, several levels deep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-62", + "metadata": {}, + "outputs": [], + "source": [ + "here = rec.headers(\"local\")\n", + "\n", + "print(here.about)\n", + "print(f\"{len(here)} files opened, {len(here.files)} of them distinct, {here.depth} levels deep\")\n", + "print()\n", + "print(here.tree(18))\n", + "print(\" ...\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-63", + "metadata": {}, + "source": [ + "That is what a [translation unit](https://github.com/tamnd/gcc-internals/blob/main/GLOSSARY.md#translation-unit) is. Not the file you wrote: the file you wrote with\n", + "everything it dragged in, which for a program whose body is one `puts` call is thirty eight\n", + "files and some tens of thousands of lines.\n", + "\n", + "The same two lines somewhere else." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-64", + "metadata": {}, + "outputs": [], + "source": [ + "there = rec.headers(\"elsewhere\")\n", + "\n", + "print(f\"{local.target:<28}{len(here.files):>4} distinct files\")\n", + "print(f\"{elsewhere.target:<28}{len(there.files):>4} distinct files\")\n", + "print()\n", + "print(there.tree(12))\n", + "print(\" ...\")\n", + "print()\n", + "print(\"files in common:\", set(here.files) & set(there.files) or \"none at all\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-65", + "metadata": {}, + "source": [ + "Not one file in common. Same standard header, same release, same two lines of C, and the two\n", + "trees share nothing, because one of them is an Apple SDK and the other is glibc. Every\n", + "portability question about headers is downstream of that picture.\n", + "\n", + "## Reading a header twice\n", + "\n", + "The second `#include ` in that file cost nothing, and it is worth knowing exactly what\n", + "\"nothing\" means. Four headers, differing by one line each, included twice apiece." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-66", + "metadata": {}, + "outputs": [], + "source": [ + "for name, text in sorted(rec.headers_source.items()):\n", + " print(f\"--- {name}\")\n", + " for line in text.rstrip().split(chr(10)):\n", + " print(f\" {line}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-67", + "metadata": {}, + "source": [ + "`clean.h` is the ordinary idiom. `untidy.h` has a comment after the `#endif`. `stray.h` has one\n", + "declaration after the `#endif`. `bare.h` has no guard at all. Predict which ones get opened\n", + "twice before running the next cell.\n", + "an include guard is recognised only if the guard is the whole file, in tokens." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-68", + "metadata": {}, + "outputs": [], + "source": [ + "guards = rec.headers(\"guards\")\n", + "\n", + "print(guards.text)\n", + "print(f\"opened twice: {', '.join(guards.opened_twice)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-69", + "metadata": {}, + "source": [ + "`untidy.h` was read once, and `stray.h` was read twice. The difference between them is a\n", + "comment and a declaration in the same position, which is the difference between something that\n", + "is a token and something that is not. The optimization needs the file's entire token stream to\n", + "be one conditional, and comments are gone before anything counts tokens.\n", + "\n", + "The condition itself is two lines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-70", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"guard\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-71", + "metadata": {}, + "source": [ + "`file->cmacro` is the name of the guard macro, remembered from the first read. If it is still\n", + "defined, the file is not opened. Note what that means for `#pragma once`: it is a different\n", + "mechanism with the same effect, and GCC supports both, but the guard version is the one that\n", + "works when the same header arrives through two different paths with two different `stat`\n", + "results.\n", + "\n", + "`-H` will also volunteer advice about this, and the advice has a condition on it that catches\n", + "everybody.\n", + "GCC suggests an include guard only for a file it read exactly once." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-72", + "metadata": {}, + "outputs": [], + "source": [ + "once = rec.headers(\"once\")\n", + "\n", + "print(\"--- each header included twice\")\n", + "print(f\" suggestions: {list(guards.guards_wanted) or 'none'}\")\n", + "print()\n", + "print(\"--- each header included once\")\n", + "print(f\" suggestions: {[p.rsplit('/', 1)[-1] for p in once.guards_wanted]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-73", + "metadata": {}, + "source": [ + "The run where two headers were read twice suggested nothing. The run where every header was\n", + "read once named the two that have no usable guard.\n", + "\n", + "That is not a bug, and the reason is one line of the condition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-74", + "metadata": {}, + "outputs": [], + "source": [ + "print(cuts[\"advice\"].numbered())" + ] + }, + { + "cell_type": "markdown", + "id": "f02-75", + "metadata": {}, + "source": [ + "`file->stack_count == 1`. GCC only advises about files it read exactly once, on the theory that\n", + "a file it read twice has already cost you the time and does not need a hint. Which means the\n", + "suggestion arrives for the header you have not yet had trouble with, and never for the one you\n", + "have. Worth knowing before you go looking for it in a build that is slow because of exactly\n", + "this problem.\n", + "\n", + "## Two targets, one set of rules\n", + "\n", + "One last comparison, and it is the one that says where the line is. The macro tables of these\n", + "two compilers share almost nothing. Every expansion above was recorded on both, and the\n", + "question is whether any of them came out differently.\n", + "two targets that share almost no macros expand every one of these files identically." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02-76", + "metadata": {}, + "outputs": [], + "source": [ + "for name in (\"spacing\", \"prescan\", \"paste\", \"paint\", \"invocation\"):\n", + " one = rec.expansion(name)\n", + " print(f\"{name:<12}{'same' if one.agrees else 'DIFFERENT'} {one.about}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f02-77", + "metadata": {}, + "source": [ + "Identical, all of them. Which is the shape of the whole subject: the vocabulary is the target's\n", + "and the grammar is the language's. `__SIZEOF_LONG_DOUBLE__` is a fact about a machine.\n", + "`a+EMPTY+b` becoming `a+ +b` is a fact about C, and it will be the same on a compiler for a\n", + "processor that does not exist yet.\n", + "\n", + "## Boss fight\n", + "\n", + "No new tools. Three questions, answerable from the recording:\n", + "\n", + "1. Thirty eight pairs of tokens were put next to each other with no whitespace between them.\n", + " How many came out of the preprocessor with a space in?\n", + "2. Four headers were each included twice. Which of them were actually opened twice?\n", + "3. Twenty macros are built into libcpp with a C function behind them, and a dump of every\n", + " macro prints exactly one of them. Which one, and why that one?\n", + "\n", + "Then check yourself:\n", + "\n", + "```text\n", + "python lessons/f02-tokens-not-text/grade.py\n", + "```\n", + "\n", + "or, from a checkout, `just grade f02-tokens-not-text`. It takes answers on the command line\n", + "too, so `--spaces 29 --twice a.h,b.h --odd SOME_MACRO` is a whole submission. Every answer it\n", + "marks against is worked out from the recording rather than written down.\n", + "\n", + "## What to read next\n", + "\n", + "F03 is the C parser, which is the program that reads the tokens this lesson has been printing.\n", + "The handover between them is one function call, and knowing that the parser never sees a\n", + "character of your file explains a great deal about GCC's error messages.\n", + "\n", + "F01 is the lesson before this one, if you have not done it. It shows how `cc1` gets run at all.\n", + "\n", + "If you have a GCC on your machine, every measurement here is one command. `gcc -dM -E - ' | gcc -H -E - >/dev/null`\n", + "is your include tree, and it will not match this one. That is the lesson." + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lessons/f02-tokens-not-text/grade.py b/lessons/f02-tokens-not-text/grade.py new file mode 100644 index 0000000..7112529 --- /dev/null +++ b/lessons/f02-tokens-not-text/grade.py @@ -0,0 +1,135 @@ +"""The F02 boss fight, graded. + +Three questions about the recorded preprocessor output. Work them out on paper first, then +run this. It says which ones you got right and shows the evidence for each, so a wrong answer +is something to go and look at rather than a mark. + + python lessons/f02-tokens-not-text/grade.py + python lessons/f02-tokens-not-text/grade.py --spaces 29 --twice a,b --odd NAME + +Nothing here is hardcoded. Every answer is worked out from `corpora/cpp/f02.json`, so +re-recording against a newer compiler cannot leave the grader marking against a stale answer +key. That has to be true or the grader is worse than no grader. +""" + +from __future__ import annotations + +import argparse +import sys + +from gxray import cpp + + +def questions() -> dict: + """The three answers, read off the recording rather than written down.""" + rec = cpp.load("f02") + table = rec.macros("local") + missing = rec.builtin.missing_from(table) + #: The built-in that a dump of every macro does print. Worked out by subtraction rather + #: than named, because the interesting thing is that there is exactly one. + printed = [name for name in rec.builtin.array if name not in missing] + return { + "rec": rec, + "spaces": len(rec.spaced), + "unspaced": rec.unspaced, + "twice": [one.rsplit("/", 1)[-1] for one in rec.headers("guards").opened_twice], + "missing": missing, + "printed": printed, + "odd": printed[0] if len(printed) == 1 else "", + } + + +def ask(question: str, given: str | None) -> str: + """Take the answer from the command line, or ask for it if it was not given.""" + if given is not None: + return given.strip() + if not sys.stdin.isatty(): + return "" + return input(f"{question} ").strip() + + +def words(text: str) -> list[str]: + """`a, b c` as three names, in any order and with any punctuation between them.""" + return sorted(part.strip() for part in text.replace(",", " ").split() if part.strip()) + + +def mark(label: str, correct: bool, expected: str, evidence: list[str]) -> bool: + print(f"\n{'right' if correct else 'wrong'} {label}") + if not correct: + print(f" the answer is {expected}") + for line in evidence: + print(f" {line}") + return correct + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--spaces", help="how many of the probed pairs got a space between them") + parser.add_argument("--twice", help="which of the four headers were opened twice") + parser.add_argument("--odd", help="the built-in macro that -dM does print") + args = parser.parse_args(argv) + + key = questions() + rec = key["rec"] + probed = len(rec.probes) + + print(f" {len(rec.macros('local'))} macros before a line of your program is read") + print(f" {probed} pairs of tokens put next to each other with nothing between them") + print(f" {len(rec.builtin.array)} macros libcpp defines with a C function behind them") + + said_spaces = ask(f"\nOf the {probed} pairs, how many came out with a space in?", args.spaces) + said_twice = ask("Which of the four headers were opened twice?", args.twice) + said_odd = ask("Which built-in macro does -dM print?", args.odd) + + scored = [ + mark( + "how many pairs were separated", + said_spaces.strip() == str(key["spaces"]), + str(key["spaces"]), + [ + f"{key['spaces']} of {probed} got a space, and {len(key['unspaced'])} did not", + " ".join(f"{one.glued}" for one in key["unspaced"][:6]) + " came out unchanged", + "so it is not a habit of the printer. It fires on the pairs that would lex" + " as one token and on no others", + ], + ), + mark( + "which headers were read twice", + words(said_twice) == sorted(key["twice"]), + ", ".join(sorted(key["twice"])), + [ + "bare.h has no guard at all, which is the easy half", + "stray.h has a guard, and one declaration after the #endif", + "untidy.h has a guard and a comment after the #endif, and is read once", + "the optimization needs the guard to be the whole file, in tokens", + ], + ), + mark( + "the built-in that gets printed", + said_odd.strip() == key["odd"], + key["odd"], + [ + f"{len(key['missing'])} of the {len(rec.builtin.array)} are missing from -dM", + f"the one that is not is {key['odd']}", + "because it is the only one of them cpp_init_builtins also defines the" + " ordinary way, with a value it can write into the hash table", + "the others are C functions, and there is nothing to print", + ], + ), + ] + + got = sum(scored) + print(f"\n{got} of 3.") + if got == 3: + print("The one worth sitting with is the first. A space appeared in the output that is") + print("in no input file, and it appeared because of what the two things beside it are.") + print("Text does not have that property. Tokens do.") + return 0 + print("\nThe whole recording is two lines away if you want to look at it:") + print(" from gxray import cpp") + print(' print(cpp.load("f02").headers("guards").text)') + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/lessons/f02-tokens-not-text/record.py b/lessons/f02-tokens-not-text/record.py new file mode 100644 index 0000000..d48ead3 --- /dev/null +++ b/lessons/f02-tokens-not-text/record.py @@ -0,0 +1,723 @@ +"""Record what the preprocessor does, on two targets, and the libcpp code that does it. + + python lessons/f02-tokens-not-text/record.py + python lessons/f02-tokens-not-text/record.py --check + +Four kinds of evidence go into `corpora/cpp/f02.json`: + + macros `-dM -E` on an empty file, here and on x86-64 Linux, and again under four + flags, because the table a compiler starts from is target specific and the + things that change it are not the things a reader expects + expansions five small files through `-E -P`, each one an expansion rule that text + substitution cannot produce, recorded on both targets so the reader can see + that the rules travel and the vocabulary does not + probes every pair in `gxray.cpp.PASTES` put next to each other through an empty + macro, plus nine pairs that need nothing, which is the half that makes it a + rule and not a habit + headers `-H` on one `#include `, here and there, and on four headers of the + lesson's own that differ by one line after the `#endif` + +Nothing here needs a linker and nothing writes an object file. `-E` stops after the +preprocessor, which is what makes it safe to record a file with `\\x` and `1.` in it. + +The x86-64 half goes through the Compiler Explorer API and is cached in +`tools/cecache/store`, so this is a live request once and a file lookup afterwards. + +`--check` re-asserts every fact the notebook states, against what is already committed and +without running a compiler, which is what the test suite calls. +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile +from datetime import date +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT)) + +from gxray import cpp, source # noqa: E402 +from gxray.driver import CEBackend # noqa: E402 +from tools.cecache import Cache # noqa: E402 +from tools.refcheck import GCC_ROOT, PINNED_TAG # noqa: E402 + +OUT = ROOT / "corpora" / "cpp" / "f02.json" +CUTS = ROOT / "corpora" / "source" / "f02.json" + +#: The local compiler, the same Homebrew GCC 16.2.0 that F01 recorded, so a line cited from +#: `vendor/gcc` is a line in the program that produced this output. +GCC = os.environ.get("GXRAY_GCC", "gcc-16") + +#: The other one. Same release, x86-64 Linux, reached through Compiler Explorer. +CE_COMPILER = "cg162" + +#: The flag sets the macro table is dumped under. Empty first, because that is the baseline +#: every other one is a difference from. +FLAGS: tuple[tuple[str, str, str], ...] = ( + ("local", "", "Nothing asked for. This is what an empty file already knows"), + ("elsewhere", "", "The same GCC release, built for x86-64 Linux by other people"), + ("optimized", "-O2", "One flag, and the table is not one longer"), + ("c23", "-std=c23", "The flag that names a language standard, and does not change it"), + ("fast", "-ffast-math", "The flag that tells the library your arithmetic is a lie"), +) + +#: The five expansion demonstrations. Each source is a whole file, run through `-E -P` so +#: that what comes back is the expansion and nothing else. +DEMOS: tuple[tuple[str, str, str], ...] = ( + ( + "spacing", + "A space in the output that is in none of the input, twice over", + """\ +#define EMPTY +#define PLUS + +a+EMPTY+b +a PLUS +b +a+ +b +""", + ), + ( + "prescan", + "Why stringifying a macro takes two macros, and what the first one is for", + """\ +#define PLUS + +#define STR(x) #x +#define XSTR(x) STR(x) +STR(PLUS) +XSTR(PLUS) +""", + ), + ( + "paste", + "The one operator that makes two tokens into one, and what it costs", + """\ +#define CAT(x, y) x ## y +#define PLUS + +CAT(a, b) +CAT(PLUS, PLUS) +""", + ), + ( + "paint", + "A macro that names itself, and one that names a macro that names it back", + """\ +#define foo foo + 1 +#define A B +#define B A +foo +A +""", + ), + ( + "invocation", + "A function-like macro is not expanded unless the next token is an open bracket", + """\ +#define f(x) [x] +f(1) +f +f (2) +""", + ), +) + +#: The four headers, which differ from each other by one line. `stray.h` is the whole point: +#: one declaration after the `#endif` and the file is opened again on every `#include`. +HEADERS: dict[str, str] = { + "clean.h": "#ifndef CLEAN_H\n#define CLEAN_H\nint clean_thing;\n#endif\n", + "untidy.h": ( + "#ifndef UNTIDY_H\n#define UNTIDY_H\nint untidy_thing;\n#endif\n" + "/* a comment, outside the guard */\n" + ), + "stray.h": ( + "#ifndef STRAY_H\n#define STRAY_H\nint stray_thing;\n#endif\ntypedef int stray_t;\n" + ), + "bare.h": "int bare_thing;\n", +} + +#: The file that includes each of them twice, which is the experiment. +GUARDS_C = "".join(f'#include "{name}"\n#include "{name}"\n' for name in HEADERS) + "int t;\n" + +#: The same four, each included once. GCC only names a file as wanting a guard if it read it +#: exactly once (libcpp/files.cc:2217), so the advice arrives for the file you have not yet +#: had trouble with, and never for the one you have. +ONCE_C = "".join(f'#include "{name}"\n' for name in HEADERS) + "int t;\n" + +#: One `#include `, twice, which is the number that surprises people. +STDIO_C = '#include \n#include \nint main(void) { return puts("x") < 0; }\n' + +#: The program the macro tables are dumped from. A comment rather than an empty file, because +#: the far end refuses a file with nothing in it, and because a comment is the one thing a +#: reader can be sure defines no macros: it is gone before the table is printed. +NOTHING = "/* not one declaration */\n" + +#: Where each span comes from. `first` and `last` are inclusive lines in the pinned tree and +#: `cite` is asserted against `first`, so a span that moves cannot keep a citation pointing +#: at code that is no longer there. +SPANS: tuple[dict, ...] = ( + { + "name": "padding", + "path": "libcpp/include/cpplib.h", + "first": 152, + "last": 164, + "about": "The end of the token type list, and the one that is whitespace", + "cite": "libcpp/include/cpplib.h:152@releases/gcc-16.2.0", + }, + { + "name": "token", + "path": "libcpp/include/cpplib.h", + "first": 261, + "last": 294, + "about": "What a token is: a location, a type, some flags, and one union", + "cite": "libcpp/include/cpplib.h:261@releases/gcc-16.2.0", + }, + { + "name": "avoid-paste", + "path": "libcpp/lex.cc", + "first": 4723, + "last": 4791, + "about": "The whole rule for which two tokens cannot be printed next to each other", + "cite": "libcpp/lex.cc:4723@releases/gcc-16.2.0", + }, + { + "name": "spacing", + "path": "gcc/c-family/c-ppoutput.cc", + "first": 244, + "last": 268, + "about": "The three reasons a space is printed, and the comment that admits it", + "cite": "gcc/c-family/c-ppoutput.cc:244@releases/gcc-16.2.0", + }, + { + "name": "markers", + "path": "gcc/c-family/c-ppoutput.cc", + "first": 618, + "last": 628, + "about": "Where a line marker comes from, and the two digits nothing passes in", + "cite": "gcc/c-family/c-ppoutput.cc:618@releases/gcc-16.2.0", + }, + { + "name": "marker-flags", + "path": "gcc/doc/cpp.texi", + "first": 4072, + "last": 4088, + "about": "What each digit means, from the one place in the tree that says so", + "cite": "gcc/doc/cpp.texi:4072@releases/gcc-16.2.0", + }, + { + "name": "dump", + "path": "gcc/c-family/c-ppoutput.cc", + "first": 903, + "last": 918, + "about": "Why -dM does not print the five macros everybody can name", + "cite": "gcc/c-family/c-ppoutput.cc:903@releases/gcc-16.2.0", + }, + { + "name": "builtins", + "path": "libcpp/init.cc", + "first": 448, + "last": 476, + "about": "The macros that are C functions, because no string could be right", + "cite": "libcpp/init.cc:448@releases/gcc-16.2.0", + }, + { + "name": "paint", + "path": "libcpp/macro.cc", + "first": 1589, + "last": 1590, + "about": "Two lines, and the reason a macro that names itself terminates", + "cite": "libcpp/macro.cc:1589@releases/gcc-16.2.0", + }, + { + "name": "guard", + "path": "libcpp/files.cc", + "first": 858, + "last": 861, + "about": "The include guard optimization, which is one comment and one condition", + "cite": "libcpp/files.cc:858@releases/gcc-16.2.0", + }, + { + "name": "advice", + "path": "libcpp/files.cc", + "first": 2214, + "last": 2219, + "about": "Who gets told to write a guard, and the condition that means it is not you", + "cite": "libcpp/files.cc:2214@releases/gcc-16.2.0", + }, + { + "name": "trace", + "path": "libcpp/line-map.cc", + "first": 1589, + "last": 1600, + "about": "What -H prints, and the reason a skipped file leaves no line", + "cite": "libcpp/line-map.cc:1589@releases/gcc-16.2.0", + }, +) + + +class Watched(Cache): + """The ordinary cache, keeping a note of which entries went through it. + + `tools.tier0.orphans` insists the registry accounts for the store exactly, and it works + that out from an experiment's corpus entry. This lesson's requests are not corpus + entries, so the list has to come from here instead. + """ + + def __post_init__(self) -> None: + super().__post_init__() + self.used: list[str] = [] + + def fetch(self, key: str, send) -> dict: + self.used.append(key) + return super().fetch(key, send) + + +def run(argv: list[str], cwd: Path) -> subprocess.CompletedProcess: + return subprocess.run(argv, cwd=cwd, capture_output=True, text=True, timeout=120, check=False) + + +def scrub(text: str, work: Path) -> str: + """Take the recording machine out of the recording. + + Only the directory the recorder ran in, which is a temporary one with a different name + on every run and would make two recordings of the same command look like a difference. + On this platform the same directory has two names, one of them a symbolic link, and GCC + prints whichever one it resolved, so both go. + + The SDK and compiler paths stay. Where your headers actually are is the subject of one + of the sections, and a lesson that hid it would be teaching nothing. + """ + for where in (str(work.resolve()), str(work)): + text = text.replace(where + "/", "").replace(where, ".") + return text + + +def preprocess(work: Path, name: str, text: str, *args: str) -> str: + """One file through `-E`, with the result on stdout and nothing else run.""" + (work / name).write_text(text, encoding="utf-8") + done = run([GCC, "-E", *args, name], work) + if done.returncode != 0: + raise SystemExit(f"{GCC} -E {' '.join(args)} {name} failed:\n{done.stderr}") + return done.stdout + + +def macro_text(work: Path, flags: str) -> str: + """Every macro defined before a line of the program is read.""" + args = ["-dM", "-E", "-x", "c", "-", *flags.split()] + done = subprocess.run( + [GCC, *args], cwd=work, input=NOTHING, capture_output=True, text=True, check=False + ) + if done.returncode != 0 or not done.stdout.strip(): + raise SystemExit(f"{GCC} -dM printed nothing:\n{done.stderr}") + return done.stdout + + +def probe_source() -> tuple[str, list[tuple[str, str, str, str]]]: + """A file that puts every pair next to each other, and the list of what it asked. + + `ID(x) x` rather than an empty macro, because an empty macro between two identifiers is + not between anything: `xEy` is one identifier and the preprocessor never sees a pair at + all. Wrapping each side in a macro call is the only way to make two tokens adjacent + without a character of whitespace anywhere in the line. + """ + asked = [(one.left, one.right, one.case, one.about) for one in cpp.PASTES] + kept = "nothing, and that is the point" + asked += [(left, right, "", kept) for left, right in cpp.KEPT_TOGETHER] + lines = ["#define ID(x) x"] + [f"ID({left})ID({right})" for left, right, _, _ in asked] + return "\n".join(lines) + "\n", asked + + +def probes(work: Path, back: CEBackend) -> list[dict]: + """Every pair, run, with the output line each one produced kept next to it.""" + text, asked = probe_source() + got = [line for line in preprocess(work, "probe.c", text, "-P").split("\n") if line.strip()] + if len(got) != len(asked): + raise SystemExit(f"probed {len(asked)} pairs and got {len(got)} lines back") + return [ + {"left": left, "right": right, "case": case, "about": about, "output": line} + for (left, right, case, about), line in zip(asked, got, strict=True) + ] + + +def elsewhere_output(back: CEBackend, text: str, *args: str) -> str: + """The same file through the x86-64 Linux compiler. + + Compiler Explorer hands preprocessed output back in the field it would otherwise put + assembly in, because from its side `-E` is a compilation whose output file happens to + contain C. + """ + result = back.compile(text, *args) + if not result.asm.strip(): + raise SystemExit(f"{CE_COMPILER} returned nothing for {args}:\n{result.stderr[:2000]}") + return result.asm if result.asm.endswith("\n") else result.asm + "\n" + + +def builtin() -> dict: + """The macros libcpp defines in C rather than in a string, counted in the pinned tree. + + `array` is `builtin_array`, the ones with a C function behind them. `fixed` is the ones + `cpp_init_builtins` defines with a value it can write down, which is why `__STDC__` is + in a dump of every macro and `__FILE__` is not. + """ + text = (GCC_ROOT / "libcpp" / "init.cc").read_text(encoding="utf-8", errors="replace") + block = text[text.index("static const struct builtin_macro builtin_array[]") :] + block = block[: block.index("\n};")] + array = re.findall(r'B\s*\(\s*"([^"]+)"', block) + fixed = re.findall(r'_cpp_define_builtin\s*\(\s*pfile,\s*"(\w+)', text) + return {"array": array, "fixed": sorted(set(fixed))} + + +def record() -> dict: + version = run([GCC, "--version"], ROOT).stdout.splitlines()[0] + target = run([GCC, "-dumpmachine"], ROOT).stdout.strip() + watched = Watched() + back = CEBackend(CE_COMPILER, cache=watched) + remote_version, remote_target = back.version(), back.target() + + with tempfile.TemporaryDirectory(prefix="f02-") as tmp: + work = Path(tmp) + for name, text in HEADERS.items(): + (work / name).write_text(text, encoding="utf-8") + + macros = {} + for label, flags, about in FLAGS: + if label == "elsewhere": + text = elsewhere_output(back, NOTHING, "-dM", "-E") + macros[label] = { + "text": text, + "flags": flags, + "compiler": remote_version, + "target": remote_target, + "about": about, + } + continue + macros[label] = { + "text": macro_text(work, flags), + "flags": flags, + "compiler": version, + "target": target, + "about": about, + } + + expansions = {} + for name, about, text in DEMOS: + expansions[name] = { + "about": about, + "source": text, + "output": preprocess(work, f"{name}.c", text, "-P"), + "elsewhere": elsewhere_output(back, text, "-E", "-P"), + } + markers_c = '#include "clean.h"\nint before;\n#include "stray.h"\nint after;\n' + expansions["markers"] = { + "about": "The same file with the line markers left in, which is the default", + "source": markers_c, + "output": scrub(preprocess(work, "markers.c", markers_c), work), + "elsewhere": "", + } + + traces = { + "local": { + "text": scrub(trace(work, "stdio.c", STDIO_C), work), + "about": "One #include , on a machine with an Apple SDK on it", + }, + "elsewhere": { + "text": back.compile(STDIO_C, "-H", "-E").stderr, + "about": "The same two lines on x86-64 Linux, where the headers are glibc's", + }, + "guards": { + "text": scrub(trace(work, "guards.c", GUARDS_C), work), + "about": "Four headers of this lesson's own, each one included twice", + }, + "once": { + "text": scrub(trace(work, "once.c", ONCE_C), work), + "about": "The same four, each included once, which is when GCC gives advice", + }, + } + + return { + "recorded": date.today().isoformat(), + "tag": PINNED_TAG, + "compiler": version, + "target": target, + # Which Compiler Explorer entries this recording stands for, written by the code + # that made the requests rather than kept by hand next to it. + "cache": sorted(set(watched.used)), + "headers_source": HEADERS, + "macros": macros, + "expansions": expansions, + "probes": probes(work, back), + "headers": traces, + "builtin": builtin(), + } + + +def trace(work: Path, name: str, text: str) -> str: + """`-H` on one file. The tree goes to stderr and the preprocessed output is thrown away.""" + (work / name).write_text(text, encoding="utf-8") + done = run([GCC, "-H", "-E", "-o", os.devnull, name], work) + if done.returncode != 0: + raise SystemExit(f"{GCC} -H -E {name} failed:\n{done.stderr}") + return done.stderr + + +def spans() -> dict: + for spec in SPANS: + want = f"{spec['path']}:{spec['first']}@{PINNED_TAG}" + if spec["cite"] != want: + print(f"{spec['name']}: cite says {spec['cite']}, the span starts at {want}") + raise SystemExit(1) + wanted = [{k: v for k, v in spec.items() if k != "cite"} for spec in SPANS] + return source.extract(GCC_ROOT, wanted, PINNED_TAG) + + +def check(rec: cpp.Recording) -> list[str]: + """Every fact the notebook states about the recording, asserted here instead of in prose. + + Most of these are statements about GCC 16.2.0 on two targets and not about C. That is + what this function is for: the paragraph next door cannot notice it has gone stale. + """ + wrong: list[str] = [] + + def want(condition: bool, saying: str) -> None: + if not condition: + wrong.append(saying) + + local, remote = rec.macros("local"), rec.macros("elsewhere") + for label in ("local", "elsewhere", "optimized", "c23", "fast"): + table = rec.macros(label) + want(len(table) > 300, f"the {label} table has {len(table)} macros, which is too few") + want("__GNUC__" in table, f"the {label} table has no __GNUC__, so it is not GCC's") + want( + len(local) != len(remote), + f"both targets define {len(local)} macros, which makes the comparison pointless", + ) + want( + local.only_in(remote) != [] and remote.only_in(local) != [], + "the two targets now agree on every macro name, and a section compares them", + ) + want( + local.differing(remote) != [], + "no macro is defined on both targets to a different value, and a section shows some", + ) + + #: The flag deltas. Each one is a claim in the notebook about what a flag did. + optimized = rec.macros("optimized") + want( + optimized.only_in(local) == ["__OPTIMIZE__"], + f"-O2 now adds {optimized.only_in(local)}, and the section says it adds __OPTIMIZE__", + ) + want( + local.only_in(optimized) == ["__NO_INLINE__"], + f"-O2 now removes {local.only_in(optimized)}, and the section says __NO_INLINE__", + ) + want( + len(optimized) == len(local), + f"-O2 changes the count from {len(local)} to {len(optimized)}, and the section says" + " counting is the wrong question", + ) + c23 = rec.macros("c23") + want( + c23.only_in(local) == ["__STRICT_ANSI__"], + f"-std=c23 now adds {c23.only_in(local)}, and the section says only __STRICT_ANSI__", + ) + want( + c23.differing(local) == [], + f"-std=c23 now changes {c23.differing(local)}, and the section says it changes no value", + ) + want( + local["__STDC_VERSION__"].body == c23["__STDC_VERSION__"].body == "202311L", + "__STDC_VERSION__ is no longer 202311L with and without -std=c23, and a section says" + " asking for C23 is not what put it there", + ) + fast = rec.macros("fast") + want( + "__FAST_MATH__" in fast, + "-ffast-math no longer defines __FAST_MATH__, which is how a header hears about it", + ) + want( + len(fast.only_in(local)) > 3 and fast.differing(local) != [], + f"-ffast-math now adds {len(fast.only_in(local))} macros and changes" + f" {len(fast.differing(local))}, and the section says one flag moves a great many", + ) + + #: The builtins. Twenty of them are C functions, and a dump of every macro prints one, + #: which is the section about the list that is not the list. + built = rec.builtin + want(len(built.array) == 20, f"builtin_array has {len(built.array)} entries, not 20") + for name in ("__FILE__", "__LINE__", "__COUNTER__", "__has_include", "_Pragma"): + want(name in built.array, f"{name} is no longer one of libcpp's built-in macros") + missing = built.missing_from(local) + want( + len(missing) == 19, + f"{len(missing)} of the built-ins are missing from a dump of every macro, not 19", + ) + want( + "__STDC__" not in missing, + "__STDC__ is now missing from the dump too, and the section says it is the exception", + ) + + #: The spacing rule, which is the lesson. + spacing = rec.expansion("spacing") + lines = spacing.pairs() + want(len(lines) == 3, f"the spacing demo has {len(lines)} lines in it, not 3") + glued = [(was, now) for was, now in lines if "+ +" in now] + want(len(glued) == 3, f"{len(glued)} of the spacing lines came out with a gap in, not 3") + want( + any(" " not in was and "+ +" in now for was, now in lines), + "no line in the spacing demo gained a space it did not have, which is the whole demo", + ) + want( + lines[0] == ("a+EMPTY+b", "a+ +b"), + f"a+EMPTY+b now comes out as {lines[0][1]!r}, and the section says a+ +b", + ) + want( + lines[1:] == [("a PLUS +b", "a + +b"), ("a+ +b", "a+ +b")], + f"the other two spacing lines now come out as {lines[1:]}", + ) + + prescan = rec.expansion("prescan") + want( + prescan.pairs()[-2][1].strip() == '"PLUS"', + f"STR(PLUS) now comes out as {prescan.pairs()[-2][1]!r}, not the name unexpanded", + ) + want( + prescan.pairs()[-1][1].strip() == '"+"', + f"XSTR(PLUS) now comes out as {prescan.pairs()[-1][1]!r}, not the expansion", + ) + + paint = rec.expansion("paint") + want( + paint.pairs()[-2][1].strip() == "foo + 1", + f"a macro naming itself now expands to {paint.pairs()[-2][1]!r}", + ) + want( + paint.pairs()[-1][1].strip() == "A", + f"two macros naming each other now expand to {paint.pairs()[-1][1]!r}", + ) + + invocation = rec.expansion("invocation") + want( + [now.strip() for _, now in invocation.pairs()][-3:] == ["[1]", "f", "[2]"], + f"the invocation demo now gives {[n.strip() for _, n in invocation.pairs()][-3:]}", + ) + + for name in ("spacing", "prescan", "paste", "paint", "invocation"): + want( + rec.expansion(name).agrees, + f"the {name} demo expands differently on the two targets, which cannot be right", + ) + + #: Every pair, and the nine that get nothing. + want( + len(rec.probes) == len(cpp.PASTES) + len(cpp.KEPT_TOGETHER), + f"{len(rec.probes)} pairs were probed, and the table asks for" + f" {len(cpp.PASTES) + len(cpp.KEPT_TOGETHER)}", + ) + for one in rec.probes: + if one.case: + want(one.spaced, f"{one.left!r} next to {one.right!r} came out as {one.output!r}") + else: + want( + not one.spaced, + f"{one.left!r} and {one.right!r} were separated, and nothing should separate them", + ) + want( + len(rec.spaced) == len(cpp.PASTES), + f"{len(rec.spaced)} pairs got a space, and the table lists {len(cpp.PASTES)}", + ) + cases = {one.case for one in cpp.PASTES} + want(len(cases) == 17, f"the table covers {len(cases)} case labels, and the section says 17") + for one in rec.probes: + if one.case: + want( + cpp.inserted_spaces(one.left + one.right, one.output.strip()) == 1, + f"{one.left}{one.right} came out as {one.output.strip()!r}, which is not the" + " same two tokens with one space between them", + ) + + #: Line markers. + found = cpp.markers(rec.expansion("markers").output) + want(len(found) > 4, f"the marker demo has {len(found)} markers in it, which is too few") + want( + any(one.entering for one in found) and any(one.returning for one in found), + "no marker in the demo says it is entering a file, or none says it is returning", + ) + want( + [one.file for one in found].count("clean.h") == 1, + "clean.h is no longer entered exactly once in the marker demo", + ) + + #: The include trees. + stdio = rec.headers("local") + want(len(stdio.files) > 20, f"one #include opened {len(stdio.files)} files, not many") + want(stdio.depth >= 4, f"the stdio tree is {stdio.depth} deep, which is not a tree") + want( + rec.headers("elsewhere").files != stdio.files, + "the two targets now include the same header files, which cannot be right", + ) + + guards = rec.headers("guards") + want( + guards.opened_twice == ["bare.h", "stray.h"], + f"the headers opened twice are {guards.opened_twice}, not bare.h and stray.h", + ) + want( + [one.path for one in guards].count("clean.h") == 1, + "a properly guarded header is now opened twice, and the section says it is not", + ) + want( + guards.guards_wanted == (), + f"-H now suggests a guard for {list(guards.guards_wanted)} in the file that includes" + " everything twice, and the section says it suggests nothing there", + ) + + once = rec.headers("once") + want( + once.opened_twice == [], + f"including each header once opened {once.opened_twice} twice, which is not once", + ) + want( + sorted(one.rsplit("/", 1)[-1] for one in once.guards_wanted) == ["bare.h", "stray.h"], + f"-H now suggests guards for {list(once.guards_wanted)}, not bare.h and stray.h", + ) + return wrong + + +def main(argv: list[str] | None = None) -> int: + ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + ap.add_argument("--check", action="store_true", help="assert against what is already there") + args = ap.parse_args(sys.argv[1:] if argv is None else argv) + + if not args.check: + if shutil.which(GCC) is None: + print(f"no {GCC} on PATH. Set GXRAY_GCC, or read B01 and build one.") + return 1 + if not (GCC_ROOT / "libcpp" / "init.cc").is_file(): + print(f"no GCC tree at {GCC_ROOT}. Run `just gcc-src` first.") + return 1 + OUT.parent.mkdir(parents=True, exist_ok=True) + OUT.write_text(json.dumps(record(), indent=1) + "\n", encoding="utf-8") + CUTS.parent.mkdir(parents=True, exist_ok=True) + CUTS.write_text(json.dumps(spans(), indent=1) + "\n", encoding="utf-8") + + rec = cpp.load("f02") + shown = source.load_extract("f02") + wrong = check(rec) + for line in wrong: + print(f" {line}") + verb = "checked" if args.check else "wrote" + sizes = ", ".join(f"{label} {len(table)}" for label, table in rec.tables.items()) + print( + f"{verb} {OUT.relative_to(ROOT)}, {len(rec.tables)} macro tables ({sizes}), " + f"{len(rec.expansions)} expansions, {len(rec.probes)} pairs, recorded {rec.recorded}" + ) + print(f"{verb} {CUTS.relative_to(ROOT)}, {len(shown)} spans, {shown.lines()} lines") + return 1 if wrong else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/site/mkdocs.yml b/site/mkdocs.yml index e9be17d..9a5e26c 100644 --- a/site/mkdocs.yml +++ b/site/mkdocs.yml @@ -82,6 +82,7 @@ nav: - The pseudocode: blueprints/NOTATION.md - BP-PIPELINE, the shape of a compilation: blueprints/BP-PIPELINE.md - BP-DRIVER, the program that runs the other programs: blueprints/BP-DRIVER.md + - BP-CPP, the preprocessor: blueprints/BP-CPP.md - BP-GIMPLE, the GIMPLE statement representation: blueprints/BP-GIMPLE.md - BP-CFG, blocks and edges: blueprints/BP-CFG.md - BP-SSA, one definition per name: blueprints/BP-SSA.md diff --git a/tests/test_cpp.py b/tests/test_cpp.py new file mode 100644 index 0000000..7926323 --- /dev/null +++ b/tests/test_cpp.py @@ -0,0 +1,413 @@ +"""The preprocessor reader. + +`gxray.cpp` reads four kinds of `gcc -E` output back into things with names on them. Almost +all of it is parsing, and the tests for parsing are the ordinary kind: a small input written +by hand, an awkward case next to it. + +Two are not ordinary. `test_pastes_covers_every_case_label_cpp_avoid_paste_has` compares the +table in this module with the switch in `libcpp/lex.cc`, because the table is the only claim +here about GCC rather than about GCC's output, and a GCC that grew a new pair would otherwise +leave a lesson saying something false with every test passing. +`test_every_pair_in_the_table_was_actually_separated` compares it with a recording, which is +the other direction: the switch could keep the label and stop firing. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +import pytest +from conftest import grader + +from gxray import cpp + +ROOT = Path(__file__).resolve().parent.parent +TREE = ROOT / "vendor" / "gcc" +LEX = TREE / "libcpp" / "lex.cc" +FILES = TREE / "libcpp" / "files.cc" +needs_tree = pytest.mark.skipif(not LEX.is_file(), reason="vendor/gcc is not checked out") + + +def recorded() -> cpp.Recording: + return cpp.load("f02") + + +# --------------------------------------------------------------------------- +# Line markers. + + +def test_a_marker_with_no_flags_is_a_line_number_and_nothing_else(): + one = cpp.markers('# 1 "hello.c"')[0] + assert (one.line, one.file, one.flags) == (1, "hello.c", ()) + assert not one.entering and not one.returning and not one.system + assert "no flags" in str(one) + + +def test_the_flags_after_a_marker_are_four_separate_facts(): + one = cpp.markers('# 61 "/usr/include/stdio.h" 1 3 4')[0] + assert one.flags == (1, 3, 4) + assert one.entering and one.system and not one.returning + assert one.meanings == [ + "entering a file", + "a system header, where warnings are suppressed", + 'to be wrapped in extern "C"', + ] + + +def test_a_hash_that_is_not_a_marker_is_not_read_as_one(): + """`#pragma` survives preprocessing and starts with the same character.""" + assert cpp.markers('#pragma once\n# 1 "a.c"\n#define X 1') == [ + cpp.Marker(line=1, file="a.c", flags=()) + ] + + +def test_a_path_with_a_quote_in_it_does_not_end_the_filename_early(): + one = cpp.markers('# 3 "od\\"d.h" 1')[0] + assert one.file == 'od\\"d.h' + assert one.entering + + +def test_the_body_is_the_output_with_the_bookkeeping_taken_out(): + text = '# 1 "a.c"\n\n\nint x;\n# 2 "b.h" 1\nint y;\n' + assert cpp.body(text) == ["int x;", "int y;"] + + +# --------------------------------------------------------------------------- +# Macro tables. + + +def test_a_bracket_touching_the_name_is_what_makes_a_macro_function_like(): + """`#define f (x) x` is not a function-like macro, and the space is the whole reason.""" + table = cpp.parse_macros("#define f(x) x\n#define g (x) x\n") + assert table["f"].function_like and table["f"].params == "(x)" + assert not table["g"].function_like and table["g"].body == "(x) x" + + +def test_a_macro_defined_to_nothing_is_defined(): + table = cpp.parse_macros("#define __STDC__ 1\n#define GUARD\n") + assert table.empty == ["GUARD"] + assert "GUARD" in table + assert table["GUARD"].body == "" + + +def test_a_dollar_is_a_legal_character_in_a_macro_name_and_a_target_uses_it(): + assert cpp.parse_macros("#define __APPLE_CC__ 6000\n#define $x 1\n").names == [ + "$x", + "__APPLE_CC__", + ] + + +def test_a_line_that_is_not_a_define_is_an_error_and_not_a_shrug(): + """The value of this table is that it is exhaustive, so a line it skipped would make + every count in the lesson quietly wrong.""" + with pytest.raises(cpp.CppError, match="not a definition"): + cpp.parse_macros("#define A 1\n\n") + + +def test_a_missing_macro_says_which_target_does_not_have_it(): + table = cpp.parse_macros("#define A 1\n", target="aarch64-apple-darwin24") + with pytest.raises(cpp.CppError, match="aarch64-apple-darwin24"): + table["__x86_64__"] + + +def test_the_set_operations_are_what_two_targets_are_for(): + here = cpp.parse_macros("#define A 1\n#define SIZE 8\n#define ARM 1\n") + there = cpp.parse_macros("#define A 1\n#define SIZE 16\n#define X86 1\n") + assert here.only_in(there) == ["ARM"] + assert there.only_in(here) == ["X86"] + assert here.shared(there) == ["A", "SIZE"] + assert here.differing(there) == ["SIZE"] + + +# --------------------------------------------------------------------------- +# Include traces. + + +TRACE = """\ +. /usr/include/stdio.h +.. /usr/include/features.h +... /usr/include/wordsize.h +.. /usr/include/types.h +. mine.h +Multiple include guards may be useful for: +/usr/include/wordsize.h +""" + + +def test_the_dots_are_the_depth_and_the_rest_of_the_line_is_the_path(): + got = cpp.parse_trace(TRACE) + assert len(got) == 5 + assert got.depth == 3 + assert got.includes[2] == cpp.Include(depth=3, path="/usr/include/wordsize.h") + assert got.names[-1] == "mine.h" + + +def test_what_a_header_dragged_in_is_everything_under_it_until_the_depth_drops(): + got = cpp.parse_trace(TRACE) + under = got.under("/usr/include/stdio.h") + assert [one.name for one in under] == ["features.h", "wordsize.h", "types.h"] + assert got.under("mine.h") == [] + + +def test_the_trailer_is_advice_and_is_not_another_file_being_opened(): + got = cpp.parse_trace(TRACE) + assert got.guards_wanted == ("/usr/include/wordsize.h",) + assert "/usr/include/wordsize.h" in got.files + assert len(got) == 5 + + +def test_a_file_opened_twice_is_two_lines_and_that_is_the_whole_guard_story(): + got = cpp.parse_trace(". a.h\n. a.h\n. b.h\n") + assert got.opened_twice == ["a.h"] + assert len(got) == 3 and len(got.files) == 2 + + +# --------------------------------------------------------------------------- +# Expansions. + + +def test_pairing_drops_the_directives_because_they_produce_no_output_line(): + one = cpp.Expansion("t", "", "#define E\na+E+b\n", "a+ +b\n") + assert one.pairs() == [("a+E+b", "a+ +b")] + + +def test_pairing_refuses_rather_than_lining_a_line_up_with_somebody_elses_answer(): + one = cpp.Expansion("t", "", "a\nb\n", "a\n") + with pytest.raises(cpp.CppError, match="no line can be paired"): + one.pairs() + + +def test_two_targets_agreeing_ignores_the_whitespace_at_the_end_of_a_line(): + assert cpp.Expansion("t", "", "x\n", "a + b\n", "a + b \n").agrees + assert not cpp.Expansion("t", "", "x\n", "a + b\n", "a+b\n").agrees + + +def test_counting_inserted_spaces_refuses_when_something_other_than_space_moved(): + assert cpp.inserted_spaces("++", "+ +") == 1 + with pytest.raises(cpp.CppError, match="not the source plus spaces"): + cpp.inserted_spaces("a+b", "a+c") + + +# --------------------------------------------------------------------------- +# The recording. + + +def test_the_recording_has_five_tables_of_one_release_on_two_targets(): + rec = recorded() + assert "16.2.0" in rec.compiler + assert sorted(rec.tables) == ["c23", "elsewhere", "fast", "local", "optimized"] + assert rec.macros("local").target != rec.macros("elsewhere").target + for label in rec.tables: + assert len(rec.macros(label)) > 300, label + + +def test_asking_for_a_table_that_is_not_there_says_what_is(): + with pytest.raises(cpp.CppError, match="local"): + recorded().macros("windows") + + +def test_two_targets_of_one_release_disagree_about_how_wide_a_long_double_is(): + """The comparison the lesson is built on. Same compiler, same language, same flags.""" + here, there = recorded().macros("local"), recorded().macros("elsewhere") + assert here["__SIZEOF_LONG_DOUBLE__"].body != there["__SIZEOF_LONG_DOUBLE__"].body + assert here["__STDC_VERSION__"].body == there["__STDC_VERSION__"].body + assert len(here.differing(there)) > 20 + + +def test_the_flag_that_names_a_standard_does_not_change_the_standard(): + rec = recorded() + local, c23 = rec.macros("local"), rec.macros("c23") + assert c23.only_in(local) == ["__STRICT_ANSI__"] + assert c23.differing(local) == [] + + +def test_optimizing_adds_one_macro_and_removes_one_so_the_count_says_nothing(): + rec = recorded() + local, fast = rec.macros("local"), rec.macros("optimized") + assert fast.only_in(local) == ["__OPTIMIZE__"] + assert local.only_in(fast) == ["__NO_INLINE__"] + assert len(fast) == len(local) + + +def test_almost_every_built_in_macro_is_missing_from_a_dump_of_every_macro(): + """`-dM` prints the hash table, and nineteen of the twenty are C functions that are not + in it. `__STDC__` is the one that is, because it is also defined the ordinary way.""" + rec = recorded() + missing = rec.builtin.missing_from(rec.macros("local")) + assert len(rec.builtin.array) == 20 + assert len(missing) == 19 + assert "__FILE__" in missing and "__STDC__" not in missing + assert "__STDC__" in rec.builtin.fixed + + +def test_every_pair_in_the_table_was_actually_separated(): + """The other half of the bargain with `cpp_avoid_paste`: the label can survive while the + behaviour goes away, and then only a recording notices.""" + rec = recorded() + assert len(rec.probes) == len(cpp.PASTES) + len(cpp.KEPT_TOGETHER) + for one in rec.probes: + assert one.spaced == bool(one.case), f"{one.left!r} {one.right!r} -> {one.output!r}" + assert len(rec.spaced) == len(cpp.PASTES) + assert len(rec.unspaced) == len(cpp.KEPT_TOGETHER) + + +def test_a_separated_pair_is_the_same_two_tokens_with_exactly_one_space_added(): + for one in recorded().spaced: + assert cpp.inserted_spaces(one.glued, one.output.strip()) == 1 + + +def test_looking_up_a_pair_nobody_probed_says_so(): + with pytest.raises(cpp.CppError, match="nothing probed"): + recorded().probe("@", "@") + + +def test_a_guarded_header_is_read_once_and_an_unguarded_one_is_read_every_time(): + guards = recorded().headers("guards") + assert guards.opened_twice == ["bare.h", "stray.h"] + assert [one.path for one in guards].count("clean.h") == 1 + + +def test_a_comment_after_the_endif_does_not_cost_the_guard_optimization(): + """`untidy.h` has one, and is still read once. `stray.h` has a declaration there and is + read twice, which is the difference between a token and a character.""" + guards = recorded().headers("guards") + assert "untidy.h" not in guards.opened_twice + assert "stray.h" in guards.opened_twice + + +def test_the_advice_arrives_for_the_file_you_have_not_had_trouble_with(): + """`-H` names a file as wanting a guard only if it read it exactly once, so the file + being read twice right now is the one it says nothing about.""" + rec = recorded() + assert rec.headers("guards").guards_wanted == () + named = sorted(one.rsplit("/", 1)[-1] for one in rec.headers("once").guards_wanted) + assert named == ["bare.h", "stray.h"] + assert rec.headers("once").opened_twice == [] + + +def test_one_include_of_stdio_opens_a_great_many_files_on_both_targets(): + rec = recorded() + here, there = rec.headers("local"), rec.headers("elsewhere") + assert len(here.files) > 20 and len(there.files) > 20 + assert here.depth > 3 and there.depth > 3 + assert set(here.files) & set(there.files) == set() + + +def test_the_marker_demo_enters_and_returns_from_every_header_it_names(): + found = cpp.markers(recorded().expansion("markers").output) + entered = [one.file for one in found if one.entering] + assert entered == ["clean.h", "stray.h"] + assert [one.file for one in found if one.returning] == ["markers.c", "markers.c"] + + +def test_the_expansion_rules_are_the_same_on_two_targets_the_macros_are_not(): + rec = recorded() + for name in ("spacing", "prescan", "paste", "paint", "invocation"): + assert rec.expansion(name).agrees, name + + +def test_stringifying_a_macro_takes_two_macros_and_the_recording_shows_why(): + rec = recorded() + assert [now.strip() for _, now in rec["prescan"].pairs()] == ['"PLUS"', '"+"'] + + +def test_a_macro_that_names_itself_stops_and_a_pair_that_name_each_other_stop_too(): + rec = recorded() + assert [now.strip() for _, now in rec["paint"].pairs()] == ["foo + 1", "A"] + + +def test_a_function_like_macro_without_a_bracket_after_it_is_just_a_word(): + rec = recorded() + assert [now.strip() for _, now in rec["invocation"].pairs()] == ["[1]", "f", "[2]"] + + +def test_the_output_gains_a_space_that_is_in_no_input_file(): + """One line, and the reason the lesson exists.""" + was, now = recorded()["spacing"].pairs()[0] + assert " " not in was + assert now == "a+ +b" + + +# --------------------------------------------------------------------------- +# Against the source. + + +@needs_tree +def test_pastes_covers_every_case_label_cpp_avoid_paste_has(): + """The check that keeps the table honest. + + Every `case` in `cpp_avoid_paste` is a reason two tokens cannot be printed together. + `PASTES` claims one witness for each of them, apart from the six about string literals + and pragmas that a `-E` of a C file cannot produce. If GCC adds a case, this fails. + """ + whole = LEX.read_text(encoding="utf-8").split("\n") + first = next(n for n, line in enumerate(whole, 1) if line.startswith("cpp_avoid_paste ")) + last = next(n for n in range(first, len(whole) + 1) if whole[n - 1] == "}") + body = "\n".join(whole[first - 1 : last]) + labels = set(re.findall(r"case (CPP_\w+):", body)) + + #: A user-defined literal suffix on a string is a C++ thing, and `CPP_PRAGMA` is a token + #: the preprocessor makes for `_Pragma` rather than one a file can contain. Neither can + #: be probed by putting two tokens next to each other in a C file. + unprobeable = { + "CPP_PRAGMA", + "CPP_STRING", + "CPP_WSTRING", + "CPP_UTF8STRING", + "CPP_STRING16", + "CPP_STRING32", + } + #: Not a `case`. Everything up to `CPP_LAST_EQ` in the token list pastes with `=`, which + #: the function handles with a comparison before the switch starts. + early = {"CPP_LAST_EQ"} + + assert {one.case for one in cpp.PASTES} == (labels - unprobeable) | early + assert "(int) a <= (int) CPP_LAST_EQ" in body + + +@needs_tree +def test_the_advice_condition_is_the_one_the_recording_demonstrates(): + """`stack_count == 1`, which is why including a header twice silences the suggestion.""" + body = FILES.read_text(encoding="utf-8") + assert "file->stack_count == 1" in body + assert cpp.GUARDS_WANTED in body + + +@needs_tree +def test_every_marker_flag_this_module_explains_is_one_gcc_documents(): + doc = (TREE / "gcc" / "doc" / "cpp.texi").read_text(encoding="utf-8") + where = doc.index("Source file name and line number information") + said = doc[where : where + 4000] + for flag in cpp.MARKER_FLAGS: + assert f"@samp{{{flag}}}" in said, flag + + +# --------------------------------------------------------------------------- +# The boss fight. + + +def test_the_grader_works_its_answers_out_of_the_recording(): + key = grader("f02-tokens-not-text").questions() + rec = recorded() + assert key["spaces"] == len(rec.spaced) + assert key["twice"] == ["bare.h", "stray.h"] + assert key["odd"] == "__STDC__" + + +def test_the_grader_marks_a_right_answer_right_however_it_is_punctuated(): + module = grader("f02-tokens-not-text") + assert module.words("bare.h, stray.h") == ["bare.h", "stray.h"] + assert module.words(" stray.h bare.h ") == ["bare.h", "stray.h"] + + +def test_the_grader_scores_the_answers_the_lesson_leads_you_to(): + module = grader("f02-tokens-not-text") + rec = recorded() + assert ( + module.main( + ["--spaces", str(len(rec.spaced)), "--twice", "bare.h,stray.h", "--odd", "__STDC__"] + ) + == 0 + ) + assert module.main(["--spaces", "0", "--twice", "clean.h", "--odd", "__FILE__"]) == 1 diff --git a/tests/test_tier0.py b/tests/test_tier0.py index d683769..3ef53b4 100644 --- a/tests/test_tier0.py +++ b/tests/test_tier0.py @@ -181,9 +181,13 @@ def test_the_store_holds_nothing_nobody_asks_for(): F01 adds one, the same way. Its recorder makes two requests, a `-dumpspecs` on the x86-64 build and the `cg162` probe behind it, and the probe is one somebody else had already paid for. + + F02 adds seven. Its recorder sends eight keys, the x86-64 macro table, the five expansion + demonstrations, one `-H` trace of `#include `, and the same `cg162` probe, which + somebody else had already paid for again. """ assert orphans(REGISTRY) == [] - assert len(set().union(*(keys(x) for x in REGISTRY))) == 43 + assert len(set().union(*(keys(x) for x in REGISTRY))) == 50 def _ce_recording_recipes(): diff --git a/tools/cecache/store/32/32e12e027eab29cf8c9c8bdded42e8ab.json b/tools/cecache/store/32/32e12e027eab29cf8c9c8bdded42e8ab.json new file mode 100644 index 0000000..dec7880 --- /dev/null +++ b/tools/cecache/store/32/32e12e027eab29cf8c9c8bdded42e8ab.json @@ -0,0 +1,2841 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "# 0 \"/app/example.c\"" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/app//\"" + }, + { + "labels": [], + "source": null, + "text": "# 0 \"\"" + }, + { + "labels": [], + "source": null, + "text": "# 0 \"\"" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/stdc-predef.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 0 \"\" 2" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/app/example.c\"" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/stdio.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 28 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/libc-header-start.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 33 \"/usr/include/x86_64-linux-gnu/bits/libc-header-start.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/features.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 394 \"/usr/include/features.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/features-time64.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 20 \"/usr/include/features-time64.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/wordsize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 21 \"/usr/include/features-time64.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 19 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/wordsize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 20 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 22 \"/usr/include/features-time64.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 395 \"/usr/include/features.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 502 \"/usr/include/features.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/sys/cdefs.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 576 \"/usr/include/x86_64-linux-gnu/sys/cdefs.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/wordsize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 577 \"/usr/include/x86_64-linux-gnu/sys/cdefs.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/long-double.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 578 \"/usr/include/x86_64-linux-gnu/sys/cdefs.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 503 \"/usr/include/features.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 526 \"/usr/include/features.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/gnu/stubs.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 10 \"/usr/include/x86_64-linux-gnu/gnu/stubs.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/gnu/stubs-64.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 11 \"/usr/include/x86_64-linux-gnu/gnu/stubs.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 527 \"/usr/include/features.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 34 \"/usr/include/x86_64-linux-gnu/bits/libc-header-start.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 29 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 229 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 229 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef long unsigned int size_t;" + }, + { + "labels": [], + "source": null, + "text": "# 35 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stdarg.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 40 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stdarg.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef __builtin_va_list __gnuc_va_list;" + }, + { + "labels": [], + "source": null, + "text": "# 38 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 27 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/wordsize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 28 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 19 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/wordsize.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 20 \"/usr/include/x86_64-linux-gnu/bits/timesize.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 29 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned char __u_char;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned short int __u_short;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __u_int;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __u_long;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef signed char __int8_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned char __uint8_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef signed short int __int16_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned short int __uint16_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef signed int __int32_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __uint32_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef signed long int __int64_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __uint64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef __int8_t __int_least8_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __uint8_t __uint_least8_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __int16_t __int_least16_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __uint16_t __uint_least16_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __int32_t __int_least32_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __uint32_t __uint_least32_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __int64_t __int_least64_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef __uint64_t __uint_least64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __quad_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __u_quad_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __intmax_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __uintmax_t;" + }, + { + "labels": [], + "source": null, + "text": "# 141 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/typesizes.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 142 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/time64.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 143 \"/usr/include/x86_64-linux-gnu/bits/types.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __dev_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __uid_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __gid_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __ino_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __ino64_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __mode_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __nlink_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __off_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __off64_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef int __pid_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef struct { int __val[2]; } __fsid_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __clock_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __rlim_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __rlim64_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __id_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __time_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __useconds_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __suseconds_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __suseconds64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef int __daddr_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef int __key_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef int __clockid_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef void * __timer_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __blksize_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __blkcnt_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __blkcnt64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __fsblkcnt_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __fsblkcnt64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __fsfilcnt_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __fsfilcnt64_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __fsword_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __ssize_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __syscall_slong_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned long int __syscall_ulong_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef __off64_t __loff_t;" + }, + { + "labels": [], + "source": null, + "text": "typedef char *__caddr_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef long int __intptr_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef unsigned int __socklen_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef int __sig_atomic_t;" + }, + { + "labels": [], + "source": null, + "text": "# 40 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 13 \"/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef struct" + }, + { + "labels": [], + "source": null, + "text": "{" + }, + { + "labels": [], + "source": null, + "text": " int __count;" + }, + { + "labels": [], + "source": null, + "text": " union" + }, + { + "labels": [], + "source": null, + "text": " {" + }, + { + "labels": [], + "source": null, + "text": " unsigned int __wch;" + }, + { + "labels": [], + "source": null, + "text": " char __wchb[4];" + }, + { + "labels": [], + "source": null, + "text": " } __value;" + }, + { + "labels": [], + "source": null, + "text": "} __mbstate_t;" + }, + { + "labels": [], + "source": null, + "text": "# 6 \"/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef struct _G_fpos_t" + }, + { + "labels": [], + "source": null, + "text": "{" + }, + { + "labels": [], + "source": null, + "text": " __off_t __pos;" + }, + { + "labels": [], + "source": null, + "text": " __mbstate_t __state;" + }, + { + "labels": [], + "source": null, + "text": "} __fpos_t;" + }, + { + "labels": [], + "source": null, + "text": "# 41 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 10 \"/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef struct _G_fpos64_t" + }, + { + "labels": [], + "source": null, + "text": "{" + }, + { + "labels": [], + "source": null, + "text": " __off64_t __pos;" + }, + { + "labels": [], + "source": null, + "text": " __mbstate_t __state;" + }, + { + "labels": [], + "source": null, + "text": "} __fpos64_t;" + }, + { + "labels": [], + "source": null, + "text": "# 42 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/__FILE.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_FILE;" + }, + { + "labels": [], + "source": null, + "text": "typedef struct _IO_FILE __FILE;" + }, + { + "labels": [], + "source": null, + "text": "# 43 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/FILE.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_FILE;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef struct _IO_FILE FILE;" + }, + { + "labels": [], + "source": null, + "text": "# 44 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 35 \"/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_FILE;" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_marker;" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_codecvt;" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_wide_data;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef void _IO_lock_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "struct _IO_FILE" + }, + { + "labels": [], + "source": null, + "text": "{" + }, + { + "labels": [], + "source": null, + "text": " int _flags;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_read_ptr;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_read_end;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_read_base;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_write_base;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_write_ptr;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_write_end;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_buf_base;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_buf_end;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_save_base;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_backup_base;" + }, + { + "labels": [], + "source": null, + "text": " char *_IO_save_end;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " struct _IO_marker *_markers;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " struct _IO_FILE *_chain;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " int _fileno;" + }, + { + "labels": [], + "source": null, + "text": " int _flags2;" + }, + { + "labels": [], + "source": null, + "text": " __off_t _old_offset;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " unsigned short _cur_column;" + }, + { + "labels": [], + "source": null, + "text": " signed char _vtable_offset;" + }, + { + "labels": [], + "source": null, + "text": " char _shortbuf[1];" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " _IO_lock_t *_lock;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " __off64_t _offset;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " struct _IO_codecvt *_codecvt;" + }, + { + "labels": [], + "source": null, + "text": " struct _IO_wide_data *_wide_data;" + }, + { + "labels": [], + "source": null, + "text": " struct _IO_FILE *_freeres_list;" + }, + { + "labels": [], + "source": null, + "text": " void *_freeres_buf;" + }, + { + "labels": [], + "source": null, + "text": " size_t __pad5;" + }, + { + "labels": [], + "source": null, + "text": " int _mode;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];" + }, + { + "labels": [], + "source": null, + "text": "};" + }, + { + "labels": [], + "source": null, + "text": "# 45 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 27 \"/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef __ssize_t cookie_read_function_t (void *__cookie, char *__buf," + }, + { + "labels": [], + "source": null, + "text": " size_t __nbytes);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef __ssize_t cookie_write_function_t (void *__cookie, const char *__buf," + }, + { + "labels": [], + "source": null, + "text": " size_t __nbytes);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef int cookie_seek_function_t (void *__cookie, __off64_t *__pos, int __w);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef int cookie_close_function_t (void *__cookie);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef struct _IO_cookie_io_functions_t" + }, + { + "labels": [], + "source": null, + "text": "{" + }, + { + "labels": [], + "source": null, + "text": " cookie_read_function_t *read;" + }, + { + "labels": [], + "source": null, + "text": " cookie_write_function_t *write;" + }, + { + "labels": [], + "source": null, + "text": " cookie_seek_function_t *seek;" + }, + { + "labels": [], + "source": null, + "text": " cookie_close_function_t *close;" + }, + { + "labels": [], + "source": null, + "text": "} cookie_io_functions_t;" + }, + { + "labels": [], + "source": null, + "text": "# 48 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef __gnuc_va_list va_list;" + }, + { + "labels": [], + "source": null, + "text": "# 64 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef __off_t off_t;" + }, + { + "labels": [], + "source": null, + "text": "# 78 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "typedef __ssize_t ssize_t;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "typedef __fpos_t fpos_t;" + }, + { + "labels": [], + "source": null, + "text": "# 129 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/stdio_lim.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 130 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 149 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *stdin;" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *stdout;" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *stderr;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int remove (const char *__filename) __attribute__ ((__nothrow__ , __leaf__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int rename (const char *__old, const char *__new) __attribute__ ((__nothrow__ , __leaf__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int renameat (int __oldfd, const char *__old, int __newfd," + }, + { + "labels": [], + "source": null, + "text": " const char *__new) __attribute__ ((__nothrow__ , __leaf__));" + }, + { + "labels": [], + "source": null, + "text": "# 184 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fclose (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 194 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *tmpfile (void)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "# 211 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern char *tmpnam (char[20]) __attribute__ ((__nothrow__ , __leaf__)) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern char *tmpnam_r (char __s[20]) __attribute__ ((__nothrow__ , __leaf__)) ;" + }, + { + "labels": [], + "source": null, + "text": "# 228 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern char *tempnam (const char *__dir, const char *__pfx)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (__builtin_free, 1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fflush (FILE *__stream);" + }, + { + "labels": [], + "source": null, + "text": "# 245 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fflush_unlocked (FILE *__stream);" + }, + { + "labels": [], + "source": null, + "text": "# 264 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *fopen (const char *__restrict __filename," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __modes)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *freopen (const char *__restrict __filename," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __modes," + }, + { + "labels": [], + "source": null, + "text": " FILE *__restrict __stream) __attribute__ ((__nonnull__ (3)));" + }, + { + "labels": [], + "source": null, + "text": "# 299 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *fdopen (int __fd, const char *__modes) __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *fopencookie (void *__restrict __magic_cookie," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __modes," + }, + { + "labels": [], + "source": null, + "text": " cookie_io_functions_t __io_funcs) __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *fmemopen (void *__s, size_t __len, const char *__modes)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (fclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "# 334 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf," + }, + { + "labels": [], + "source": null, + "text": " int __modes, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf," + }, + { + "labels": [], + "source": null, + "text": " size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fprintf (FILE *__restrict __stream," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, ...) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int printf (const char *__restrict __format, ...);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int sprintf (char *__restrict __s," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, ...) __attribute__ ((__nothrow__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vfprintf (FILE *__restrict __s, const char *__restrict __format," + }, + { + "labels": [], + "source": null, + "text": " __gnuc_va_list __arg) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vprintf (const char *__restrict __format, __gnuc_va_list __arg);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vsprintf (char *__restrict __s, const char *__restrict __format," + }, + { + "labels": [], + "source": null, + "text": " __gnuc_va_list __arg) __attribute__ ((__nothrow__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int snprintf (char *__restrict __s, size_t __maxlen," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, ...)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 4)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vsnprintf (char *__restrict __s, size_t __maxlen," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 0)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vasprintf (char **__restrict __ptr, const char *__restrict __f," + }, + { + "labels": [], + "source": null, + "text": " __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 0))) ;" + }, + { + "labels": [], + "source": null, + "text": "extern int __asprintf (char **__restrict __ptr," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __fmt, ...)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 3))) ;" + }, + { + "labels": [], + "source": null, + "text": "extern int asprintf (char **__restrict __ptr," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __fmt, ...)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 2, 3))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vdprintf (int __fd, const char *__restrict __fmt," + }, + { + "labels": [], + "source": null, + "text": " __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__printf__, 2, 0)));" + }, + { + "labels": [], + "source": null, + "text": "extern int dprintf (int __fd, const char *__restrict __fmt, ...)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__printf__, 2, 3)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fscanf (FILE *__restrict __stream," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, ...) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int scanf (const char *__restrict __format, ...) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int sscanf (const char *__restrict __s," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, ...) __attribute__ ((__nothrow__ , __leaf__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 128 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn-common.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 33 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn-common.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "# 1 \"/usr/include/x86_64-linux-gnu/bits/long-double.h\" 1 3" + }, + { + "labels": [], + "source": null, + "text": "# 34 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn-common.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 129 \"/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "# 438 \"/usr/include/stdio.h\" 2 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fscanf (FILE *__restrict __stream, const char *__restrict __format, ...) __asm__ (\"\" \"__isoc23_fscanf\")" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int scanf (const char *__restrict __format, ...) __asm__ (\"\" \"__isoc23_scanf\")" + }, + { + "labels": [], + "source": null, + "text": " ;" + }, + { + "labels": [], + "source": null, + "text": "extern int sscanf (const char *__restrict __s, const char *__restrict __format, ...) __asm__ (\"\" \"__isoc23_sscanf\") __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " ;" + }, + { + "labels": [], + "source": null, + "text": "# 490 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int vfscanf (FILE *__restrict __s, const char *__restrict __format," + }, + { + "labels": [], + "source": null, + "text": " __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__scanf__, 2, 0))) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__scanf__, 1, 0))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vsscanf (const char *__restrict __s," + }, + { + "labels": [], + "source": null, + "text": " const char *__restrict __format, __gnuc_va_list __arg)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__format__ (__scanf__, 2, 0)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int vfscanf (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ (\"\" \"__isoc23_vfscanf\")" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__scanf__, 2, 0))) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg) __asm__ (\"\" \"__isoc23_vscanf\")" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__scanf__, 1, 0))) ;" + }, + { + "labels": [], + "source": null, + "text": "extern int vsscanf (const char *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ (\"\" \"__isoc23_vsscanf\") __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__format__ (__scanf__, 2, 0)));" + }, + { + "labels": [], + "source": null, + "text": "# 575 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fgetc (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int getc (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int getchar (void);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int getc_unlocked (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int getchar_unlocked (void);" + }, + { + "labels": [], + "source": null, + "text": "# 600 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fgetc_unlocked (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 611 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fputc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "extern int putc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int putchar (int __c);" + }, + { + "labels": [], + "source": null, + "text": "# 627 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fputc_unlocked (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int putc_unlocked (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "extern int putchar_unlocked (int __c);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int getw (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int putw (int __w, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__access__ (__write_only__, 1, 2))) __attribute__ ((__nonnull__ (3)));" + }, + { + "labels": [], + "source": null, + "text": "# 694 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern __ssize_t __getdelim (char **__restrict __lineptr," + }, + { + "labels": [], + "source": null, + "text": " size_t *__restrict __n, int __delimiter," + }, + { + "labels": [], + "source": null, + "text": " FILE *__restrict __stream) __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "extern __ssize_t getdelim (char **__restrict __lineptr," + }, + { + "labels": [], + "source": null, + "text": " size_t *__restrict __n, int __delimiter," + }, + { + "labels": [], + "source": null, + "text": " FILE *__restrict __stream) __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern __ssize_t getline (char **__restrict __lineptr," + }, + { + "labels": [], + "source": null, + "text": " size_t *__restrict __n," + }, + { + "labels": [], + "source": null, + "text": " FILE *__restrict __stream) __attribute__ ((__nonnull__ (3)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fputs (const char *__restrict __s, FILE *__restrict __stream)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int puts (const char *__s);" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int ungetc (int __c, FILE *__stream) __attribute__ ((__nonnull__ (2)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern size_t fread (void *__restrict __ptr, size_t __size," + }, + { + "labels": [], + "source": null, + "text": " size_t __n, FILE *__restrict __stream)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern size_t fwrite (const void *__restrict __ptr, size_t __size," + }, + { + "labels": [], + "source": null, + "text": " size_t __n, FILE *__restrict __s) __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "# 766 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern size_t fread_unlocked (void *__restrict __ptr, size_t __size," + }, + { + "labels": [], + "source": null, + "text": " size_t __n, FILE *__restrict __stream)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size," + }, + { + "labels": [], + "source": null, + "text": " size_t __n, FILE *__restrict __stream)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (4)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fseek (FILE *__stream, long int __off, int __whence)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern long int ftell (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void rewind (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 803 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fseeko (FILE *__stream, __off_t __off, int __whence)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern __off_t ftello (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 829 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fsetpos (FILE *__stream, const fpos_t *__pos) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 860 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int feof (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int ferror (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void perror (const char *__s) __attribute__ ((__cold__));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 897 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int pclose (FILE *__stream) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern FILE *popen (const char *__command, const char *__modes)" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__malloc__)) __attribute__ ((__malloc__ (pclose, 1))) ;" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__))" + }, + { + "labels": [], + "source": null, + "text": " __attribute__ ((__access__ (__write_only__, 1)));" + }, + { + "labels": [], + "source": null, + "text": "# 941 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));" + }, + { + "labels": [], + "source": null, + "text": "# 959 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "extern int __uflow (FILE *);" + }, + { + "labels": [], + "source": null, + "text": "extern int __overflow (FILE *, int);" + }, + { + "labels": [], + "source": null, + "text": "# 983 \"/usr/include/stdio.h\" 3" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 2 \"/app/example.c\" 2" + }, + { + "labels": [], + "source": null, + "text": "" + }, + { + "labels": [], + "source": null, + "text": "# 3 \"/app/example.c\"" + }, + { + "labels": [], + "source": null, + "text": "int main(void) { return puts(\"x\") < 0; }" + } + ], + "asmSize": 22089, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-H", + "-E", + "/app/example.c" + ], + "downloads": [], + "execTime": 63, + "filteredCount": 287, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 8, + "popularArguments": {}, + "processExecutionResultTime": 0.1616940014064312, + "stderr": [ + { + "text": ". /usr/include/stdio.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h" + }, + { + "text": "... /usr/include/features.h" + }, + { + "text": ".... /usr/include/features-time64.h" + }, + { + "text": "..... /usr/include/x86_64-linux-gnu/bits/wordsize.h" + }, + { + "text": "..... /usr/include/x86_64-linux-gnu/bits/timesize.h" + }, + { + "text": "...... /usr/include/x86_64-linux-gnu/bits/wordsize.h" + }, + { + "text": ".... /usr/include/x86_64-linux-gnu/sys/cdefs.h" + }, + { + "text": "..... /usr/include/x86_64-linux-gnu/bits/wordsize.h" + }, + { + "text": "..... /usr/include/x86_64-linux-gnu/bits/long-double.h" + }, + { + "text": ".... /usr/include/x86_64-linux-gnu/gnu/stubs.h" + }, + { + "text": "..... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h" + }, + { + "text": ".. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h" + }, + { + "text": ".. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stdarg.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types.h" + }, + { + "text": "... /usr/include/x86_64-linux-gnu/bits/wordsize.h" + }, + { + "text": "... /usr/include/x86_64-linux-gnu/bits/timesize.h" + }, + { + "text": ".... /usr/include/x86_64-linux-gnu/bits/wordsize.h" + }, + { + "text": "... /usr/include/x86_64-linux-gnu/bits/typesizes.h" + }, + { + "text": "... /usr/include/x86_64-linux-gnu/bits/time64.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" + }, + { + "text": "... /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/__FILE.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/FILE.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h" + }, + { + "text": ".. /usr/include/x86_64-linux-gnu/bits/stdio_lim.h" + }, + { + "text": ".. /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn.h" + }, + { + "text": "... /cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include-fixed/x86_64-linux-gnu/bits/floatn-common.h" + }, + { + "text": ".... /usr/include/x86_64-linux-gnu/bits/long-double.h" + }, + { + "text": "Multiple include guards may be useful for:" + }, + { + "text": "/cefs/17/17a2c76db590a13a8a92c74c_consolidated/compilers_c++_x86_gcc_16.2.0/lib/gcc/x86_64-linux-gnu/16.2.0/include/stddef.h" + }, + { + "text": "/usr/include/features-time64.h" + }, + { + "text": "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" + }, + { + "text": "/usr/include/x86_64-linux-gnu/bits/time64.h" + }, + { + "text": "/usr/include/x86_64-linux-gnu/bits/typesizes.h" + }, + { + "text": "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" + }, + { + "text": "/usr/include/x86_64-linux-gnu/gnu/stubs.h" + } + ], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/6e/6e056683d5f98988c2723fa1411181ea.json b/tools/cecache/store/6e/6e056683d5f98988c2723fa1411181ea.json new file mode 100644 index 0000000..2b80139 --- /dev/null +++ b/tools/cecache/store/6e/6e056683d5f98988c2723fa1411181ea.json @@ -0,0 +1,48 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "a+ +b" + }, + { + "labels": [], + "source": null, + "text": "a + +b" + }, + { + "labels": [], + "source": null, + "text": "a+ +b" + } + ], + "asmSize": 19, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-E", + "-P", + "/app/example.c" + ], + "downloads": [], + "execTime": 37, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 0, + "popularArguments": {}, + "processExecutionResultTime": 0.0025099962949752808, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/8c/8c6c8a242b28ac906e721b4315f002c7.json b/tools/cecache/store/8c/8c6c8a242b28ac906e721b4315f002c7.json new file mode 100644 index 0000000..592aec4 --- /dev/null +++ b/tools/cecache/store/8c/8c6c8a242b28ac906e721b4315f002c7.json @@ -0,0 +1,43 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "\"PLUS\"" + }, + { + "labels": [], + "source": null, + "text": "\"+\"" + } + ], + "asmSize": 11, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-E", + "-P", + "/app/example.c" + ], + "downloads": [], + "execTime": 44, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 0, + "popularArguments": {}, + "processExecutionResultTime": 0.005068998783826828, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/b0/b052b8da4cb7550d4d587e32552932fe.json b/tools/cecache/store/b0/b052b8da4cb7550d4d587e32552932fe.json new file mode 100644 index 0000000..866089a --- /dev/null +++ b/tools/cecache/store/b0/b052b8da4cb7550d4d587e32552932fe.json @@ -0,0 +1,43 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "foo + 1" + }, + { + "labels": [], + "source": null, + "text": "A" + } + ], + "asmSize": 10, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-E", + "-P", + "/app/example.c" + ], + "downloads": [], + "execTime": 36, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 0, + "popularArguments": {}, + "processExecutionResultTime": 0.0048599999863654375, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/b8/b8aad3f4e7ae4a0cd93b6026890dd086.json b/tools/cecache/store/b8/b8aad3f4e7ae4a0cd93b6026890dd086.json new file mode 100644 index 0000000..3ec1976 --- /dev/null +++ b/tools/cecache/store/b8/b8aad3f4e7ae4a0cd93b6026890dd086.json @@ -0,0 +1,48 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "[1]" + }, + { + "labels": [], + "source": null, + "text": "f" + }, + { + "labels": [], + "source": null, + "text": "[2]" + } + ], + "asmSize": 10, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-E", + "-P", + "/app/example.c" + ], + "downloads": [], + "execTime": 30, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 0, + "popularArguments": {}, + "processExecutionResultTime": 0.0026559978723526, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/bb/bb11d647f8eaf8ed57950802ec869710.json b/tools/cecache/store/bb/bb11d647f8eaf8ed57950802ec869710.json new file mode 100644 index 0000000..ba63343 --- /dev/null +++ b/tools/cecache/store/bb/bb11d647f8eaf8ed57950802ec869710.json @@ -0,0 +1,2073 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "#define __DBL_MIN_EXP__ (-1021)" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MANT_DIG__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST16_MAX__ 0xffff" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_ACQUIRE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __WCHAR_MAX__ 0x7fffffff" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MAX_10_EXP__ 4932" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_IEC_559_COMPLEX 2" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST8_TYPE__ unsigned char" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_FLOAT80__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_DENORM_MIN__ 9.18354961579912115600575419704879436e-41BF16" + }, + { + "labels": [], + "source": null, + "text": "#define __INTMAX_C(c) c ## L" + }, + { + "labels": [], + "source": null, + "text": "#define __CHAR_BIT__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT8_MAX__ 0xff" + }, + { + "labels": [], + "source": null, + "text": "#define __SCHAR_WIDTH__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __WINT_MAX__ 0xffffffffU" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MIN_EXP__ (-125)" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_NORM_MAX__ 3.38953138925153547590470800371487867e+38BF16" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MIN_10_EXP__ (-37)" + }, + { + "labels": [], + "source": null, + "text": "#define __ORDER_LITTLE_ENDIAN__ 1234" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_CHAR_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_IEC_559 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_DECIMAL_DIG__ 17" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_EVAL_METHOD__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_DECIMAL_DIG__ 17" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __SIG_ATOMIC_TYPE__ int" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MIN_10_EXP__ (-307)" + }, + { + "labels": [], + "source": null, + "text": "#define __FINITE_MATH_ONLY__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MAX_EXP__ 1024" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST8_MAX__ 0xff" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MAX_10_EXP__ 38" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_MAX_EXP__ 385" + }, + { + "labels": [], + "source": null, + "text": "#define __INT8_C(c) c" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST8_WIDTH__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __SHRT_MAX__ 0x7fff" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MAX__ 1.18973149535723176502126385303097021e+4932L" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MAX_10_EXP__ 4932" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MAX_10_EXP__ 38" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MAX_EXP__ 128" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST8_MAX__ 0xff" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_BOOL_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128" + }, + { + "labels": [], + "source": null, + "text": "#define __UINTMAX_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_DECIMAL_DIG__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __linux 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_EPSILON__ 1E-6DF" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_EVAL_METHOD_TS_18661_3__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT32_MAX__ 0xffffffffU" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_DENORM_MIN__ ((double)4.94065645841246544176568792868221372e-324L)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MIN_EXP__ (-16381)" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_MAX_EXP__ 6145" + }, + { + "labels": [], + "source": null, + "text": "#define __WINT_MIN__ 0U" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MIN_10_EXP__ (-4931)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST16_WIDTH__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __SCHAR_MAX__ 0x7f" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MANT_DIG__ 113" + }, + { + "labels": [], + "source": null, + "text": "#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)" + }, + { + "labels": [], + "source": null, + "text": "#define __INT64_C(c) c ## L" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_POINTER_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_SEQ_CST 5" + }, + { + "labels": [], + "source": null, + "text": "#define __unix 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MANT_DIG__ 53" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_EPSILON__ 1.08420217248550443400745280086994171e-19F64x" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_HOSTED__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_MIN_EXP__ (-382)" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_DIG__ 15" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_EMBED_EMPTY__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F" + }, + { + "labels": [], + "source": null, + "text": "#define __SHRT_WIDTH__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_UTF_16__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_MAX__ 9.999999E96DF" + }, + { + "labels": [], + "source": null, + "text": "#define __CHAR8_TYPE__ unsigned char" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951F64x" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __unix__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_WIDTH__ 32" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_IEC_559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_ISO_10646__ 201706L" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_CHAR8_T_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __DECIMAL_DIG__ 21" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_IEC_559_COMPLEX__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __gnu_linux__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MIN_10_EXP__ (-4931)" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MIN_EXP__ (-13)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MANT_DIG__ 53" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MANT_DIG__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_DIG__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __MMX__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_LONG_DOUBLE__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_DIG__ 18" + }, + { + "labels": [], + "source": null, + "text": "#define __BIGGEST_ALIGNMENT__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MAX_10_EXP__ 308" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_IS_IEC_60559__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MAX_10_EXP__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MAX__ ((double)1.79769313486231570814527423731704357e+308L)" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST32_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT64_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_FLOAT__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __HAVE_SPECULATION_SAFE_VALUE 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_MIN_EXP__ (-94)" + }, + { + "labels": [], + "source": null, + "text": "#define __INTPTR_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST32_MAX__ 0xffffffffU" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST16_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __MMX_WITH_SSE__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __SEG_GS 1" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_EPSILON__ 7.81250000000000000000000000000000000e-3BF16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_MIN__ 1E-95DF" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MAX_EXP__ 1024" + }, + { + "labels": [], + "source": null, + "text": "#define __WCHAR_WIDTH__ 32" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_EPSILON__ 1E-33DL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_DECIMAL_DIG__ 5" + }, + { + "labels": [], + "source": null, + "text": "#define __SSE2_MATH__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_HLE_RELEASE 131072" + }, + { + "labels": [], + "source": null, + "text": "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __amd64 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_MAX__ 9.999999999999999999999999999999999E6144D64x" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_HLE_ACQUIRE 65536" + }, + { + "labels": [], + "source": null, + "text": "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_SIZE_T__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MIN_EXP__ (-16381)" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_WINT_T__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __LONG_LONG_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MAX_EXP__ 128" + }, + { + "labels": [], + "source": null, + "text": "#define __GXX_ABI_VERSION 1021" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MIN_EXP__ (-125)" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_HAVE_DWARF2_CFI_ASM 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT16_MAX__ 0x7fff" + }, + { + "labels": [], + "source": null, + "text": "#define __x86_64 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST64_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MAX__ 3.38953138925153547590470800371487867e+38BF16" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_DENORM_MIN__ 5.96046447753906250000000000000000000e-8F16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_NORM_MAX__ 1.18973149535723176502126385303097021e+4932F64x" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_POINTER__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZE_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __LP64__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MAX_EXP__ 16384" + }, + { + "labels": [], + "source": null, + "text": "#define __DECIMAL_BID_FORMAT__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MIN_EXP__ (-1021)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MIN_10_EXP__ (-307)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MIN_10_EXP__ (-4)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_DECIMAL_DIG__ 21" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_MIN__ 1E-6143DL" + }, + { + "labels": [], + "source": null, + "text": "#define __REGISTER_PREFIX__ " + }, + { + "labels": [], + "source": null, + "text": "#define __UINT16_MAX__ 0xffff" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT8_TYPE__ unsigned char" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_DIG__ 6" + }, + { + "labels": [], + "source": null, + "text": "#define __NO_INLINE__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC_EVAL_METHOD__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MANT_DIG__ 24" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_DECIMAL_DIG__ 21" + }, + { + "labels": [], + "source": null, + "text": "#define __VERSION__ \"16.2.0\"" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT64_C(c) c ## UL" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_MIN__ 1E-6143D64x" + }, + { + "labels": [], + "source": null, + "text": "#define _STDC_PREDEF_H 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST32_MAX__ 0x7fffffff" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_INT_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MAX_EXP__ 16384" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MANT_DIG__ 24" + }, + { + "labels": [], + "source": null, + "text": "#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MIN_EXP__ (-1021)" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_IEC_60559_COMPLEX__ 201404L" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MIN__ 1.17549435082228750796873653722224568e-38BF16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_DECIMAL_DIG__ 9" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_DIG__ 33" + }, + { + "labels": [], + "source": null, + "text": "#define __INT32_C(c) c" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_EPSILON__ 1E-15DD" + }, + { + "labels": [], + "source": null, + "text": "#define __ORDER_PDP_ENDIAN__ 3412" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_MIN_EXP__ (-6142)" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST32_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST16_TYPE__ short unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_MANT_DIG__ 34" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_MAX_EXP__ 6145" + }, + { + "labels": [], + "source": null, + "text": "#define unix 1" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT64_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_DIG__ 18" + }, + { + "labels": [], + "source": null, + "text": "#define __INT8_TYPE__ signed char" + }, + { + "labels": [], + "source": null, + "text": "#define __ELF__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ASM_FLAG_OUTPUTS__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT32_TYPE__ unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_RADIX__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST16_TYPE__ short int" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_EPSILON__ 1.08420217248550443400745280086994171e-19L" + }, + { + "labels": [], + "source": null, + "text": "#define __UINTMAX_C(c) c ## UL" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_EPSILON__ 1E-33D64x" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_DIG__ 3" + }, + { + "labels": [], + "source": null, + "text": "#define __SSE_MATH__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __k8 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x" + }, + { + "labels": [], + "source": null, + "text": "#define __SIG_ATOMIC_MAX__ 0x7fffffff" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __USER_LABEL_PREFIX__ " + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_IEC_60559_BFP__ 201404L" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_PTRDIFF_T__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_LONG__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __x86_64__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MAX_EXP__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_EMBED_FOUND__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_CONSTRUCTIVE_SIZE 64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_DIG__ 15" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST64_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_EPSILON__ 9.76562500000000000000000000000000000e-4F16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MAX_10_EXP__ 38" + }, + { + "labels": [], + "source": null, + "text": "#define __LONG_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST16_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_MAX__ 9.999999999999999E384DD" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_EMBED_NOT_FOUND__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST32_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __CHAR16_TYPE__ short unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __PRAGMA_REDEFINE_EXTNAME 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143D64x" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZE_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __SEG_FS 1" + }, + { + "labels": [], + "source": null, + "text": "#define __BITINT_MAXWIDTH__ 65535" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST16_MAX__ 0x7fff" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_NORM_MAX__ 6.55040000000000000000000000000000000e+4F16" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_MANT_DIG__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32" + }, + { + "labels": [], + "source": null, + "text": "#define __SIG_ATOMIC_WIDTH__ 32" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST64_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __INT16_TYPE__ short int" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST8_TYPE__ signed char" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_VERSION__ 202311L" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_INT__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_MAX_EXP__ 97" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST8_MAX__ 0x7f" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128" + }, + { + "labels": [], + "source": null, + "text": "#define __INTPTR_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define linux 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_MIN_10_EXP__ (-37)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_DIG__ 15" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT16_C(c) c" + }, + { + "labels": [], + "source": null, + "text": "#define __PTRDIFF_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST16_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MAX__ 1.18973149535723176502126385303097021e+4932F64x" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)" + }, + { + "labels": [], + "source": null, + "text": "#define __code_model_small__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_LONG_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC32_MANT_DIG__ 7" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MANT_DIG__ 11" + }, + { + "labels": [], + "source": null, + "text": "#define __k8__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INTPTR_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT16_TYPE__ short unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __WCHAR_TYPE__ int" + }, + { + "labels": [], + "source": null, + "text": "#define __UINTPTR_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST64_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_HAS_INFINITY__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST64_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_NORM_MAX__ 3.40282346638528859811704183484516925e+38F" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MAX_EXP__ 16384" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST64_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MIN_EXP__ (-125)" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_MAX__ 0x7fffffff" + }, + { + "labels": [], + "source": null, + "text": "#define __linux__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT64_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MAX_EXP__ 128" + }, + { + "labels": [], + "source": null, + "text": "#define __ORDER_BIG_ENDIAN__ 4321" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MANT_DIG__ 53" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_FLOAT128__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __BFLT16_MANT_DIG__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_MIN__ 1E-383DD" + }, + { + "labels": [], + "source": null, + "text": "#define __WINT_TYPE__ unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_LEAST32_TYPE__ unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_SHORT__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_NORM_MAX__ 3.40282346638528859811704183484516925e+38F32" + }, + { + "labels": [], + "source": null, + "text": "#define __SSE__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MIN_EXP__ (-16381)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64X_MIN_EXP__ (-6142)" + }, + { + "labels": [], + "source": null, + "text": "#define __amd64__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __WINT_WIDTH__ 32" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST8_MAX__ 0x7f" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST64_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MAX_10_EXP__ 308" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_INT128__ 16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_MIN__ 6.10351562500000000000000000000000000e-5F16" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MAX_10_EXP__ 4932" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_RELAXED 0" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_EPSILON__ ((double)2.22044604925031308084726333618164062e-16L)" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST32_TYPE__ int" + }, + { + "labels": [], + "source": null, + "text": "#define _LP64 1" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT8_C(c) c" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MAX_EXP__ 1024" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_WCHAR_T__ 4" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT64_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC_PATCHLEVEL__ 0" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_NORM_MAX__ 1.18973149535723176508575932662800702e+4932F128" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_NORM_MAX__ 1.79769313486231570814527423731704357e+308F64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INTMAX_MAX__ 0x7fffffffffffffffL" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST8_TYPE__ signed char" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC_STDC_INLINE__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT16_HAS_DENORM__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_DECIMAL_DIG__ 17" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC_UTF_32__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_FAST8_WIDTH__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __FXSR__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_NORM_MAX__ ((double)1.79769313486231570814527423731704357e+308L)" + }, + { + "labels": [], + "source": null, + "text": "#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_DESTRUCTIVE_SIZE 64" + }, + { + "labels": [], + "source": null, + "text": "#define __INTMAX_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_DIG__ 6" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT32_C(c) c ## U" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_IS_IEC_60559__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT8_MAX__ 0x7f" + }, + { + "labels": [], + "source": null, + "text": "#define __LONG_WIDTH__ 64" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MIN__ ((double)2.22507385850720138309023271733240406e-308L)" + }, + { + "labels": [], + "source": null, + "text": "#define __INT32_MAX__ 0x7fffffff" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST32_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_NORM_MAX__ 1.79769313486231570814527423731704357e+308F32x" + }, + { + "labels": [], + "source": null, + "text": "#define __CHAR32_TYPE__ unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F" + }, + { + "labels": [], + "source": null, + "text": "#define __SSE2__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __INT32_TYPE__ int" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_DOUBLE__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_MIN_10_EXP__ (-37)" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64" + }, + { + "labels": [], + "source": null, + "text": "#define __INT_LEAST32_WIDTH__ 32" + }, + { + "labels": [], + "source": null, + "text": "#define __INTMAX_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_CONSUME 1" + }, + { + "labels": [], + "source": null, + "text": "#define __GNUC_MINOR__ 2" + }, + { + "labels": [], + "source": null, + "text": "#define __UINTMAX_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x" + }, + { + "labels": [], + "source": null, + "text": "#define __DBL_MAX_10_EXP__ 308" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951L" + }, + { + "labels": [], + "source": null, + "text": "#define __INT16_C(c) c" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_RELEASE 3" + }, + { + "labels": [], + "source": null, + "text": "#define __STDC__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __PTRDIFF_TYPE__ long int" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32X_MIN_10_EXP__ (-307)" + }, + { + "labels": [], + "source": null, + "text": "#define __UINTPTR_TYPE__ long unsigned int" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD" + }, + { + "labels": [], + "source": null, + "text": "#define __DEC128_MANT_DIG__ 34" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_MIN_10_EXP__ (-4931)" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZEOF_LONG_LONG__ 8" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT128_DECIMAL_DIG__ 36" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT32_HAS_QUIET_NAN__ 1" + }, + { + "labels": [], + "source": null, + "text": "#define __FLT_DECIMAL_DIG__ 9" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __LDBL_NORM_MAX__ 1.18973149535723176502126385303097021e+4932L" + }, + { + "labels": [], + "source": null, + "text": "#define __GCC_ATOMIC_SHORT_LOCK_FREE 2" + }, + { + "labels": [], + "source": null, + "text": "#define __SIZE_MAX__ 0xffffffffffffffffUL" + }, + { + "labels": [], + "source": null, + "text": "#define __UINT_FAST8_TYPE__ unsigned char" + }, + { + "labels": [], + "source": null, + "text": "#define __ATOMIC_ACQ_REL 4" + } + ], + "asmSize": 15425, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-dM", + "-E", + "/app/example.c" + ], + "downloads": [], + "execTime": 30, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 1, + "popularArguments": {}, + "processExecutionResultTime": 0.0026260018348693848, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/cecache/store/ef/ef9027019a0b32786c5c64e0e0652d71.json b/tools/cecache/store/ef/ef9027019a0b32786c5c64e0e0652d71.json new file mode 100644 index 0000000..f85d898 --- /dev/null +++ b/tools/cecache/store/ef/ef9027019a0b32786c5c64e0e0652d71.json @@ -0,0 +1,43 @@ +{ + "asm": [ + { + "labels": [], + "source": null, + "text": "ab" + }, + { + "labels": [], + "source": null, + "text": "PLUSPLUS" + } + ], + "asmSize": 12, + "code": 0, + "compilationOptions": [ + "-g", + "-o", + "/app/output.s", + "-fverbose-asm", + "-S", + "-fdiagnostics-color=always", + "-E", + "-P", + "/app/example.c" + ], + "downloads": [], + "execTime": 29, + "filteredCount": 0, + "inputFilename": "example.c", + "instructionSet": "amd64", + "labelDefinitions": {}, + "okToCache": true, + "optOutput": [], + "parsingTime": 0, + "popularArguments": {}, + "processExecutionResultTime": 0.002356000244617462, + "stderr": [], + "stdout": [], + "timedOut": false, + "tools": [], + "truncated": false +} diff --git a/tools/tier0/experiments.toml b/tools/tier0/experiments.toml index cb40d1e..6060849 100644 --- a/tools/tier0/experiments.toml +++ b/tools/tier0/experiments.toml @@ -421,3 +421,20 @@ check, which re-reads both tables with gxray.specs, insists neither has a form t cannot name, and asserts what each specs file did to the chain, against the committed \ recording and without a compiler.\ """ + +[[experiment]] +id = "f02-cpp" +kind = "offline" +question = "Does the preprocessor work in text, and what does its output leave out?" +lessons = ["f02-tokens-not-text"] +cache = "corpora/cpp/f02.json" +why = """ +Offline because the recording is not one compilation with dumps to compare. It is five \ +macro tables, six expansions, thirty eight probed token pairs and four include traces, and \ +its subject is the difference between two machines, so half of it has to come from a local \ +compiler that Compiler Explorer is not. The travelling half is the cache listed above, sent \ +again by lessons/f02-tokens-not-text/record.py: the x86-64 Linux macro table, the five \ +expansion demonstrations, and the -H trace of one #include . What keeps the rest \ +honest is that recorder's own check, forty odd assertions that encode what the lesson says \ +about the committed recording, run before any prose exists and re-run on every push.\ +"""