@fraczak/k 6.0.1 → 6.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +35 -0
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +64 -0
- package/DOCS/BIG_PICTURE.md +4 -8
- package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +74 -0
- package/DOCS/CONVERGENCE.md +92 -0
- package/DOCS/DIVERGENCE_DETECTION.md +24 -0
- package/DOCS/Makefile +99 -0
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +221 -0
- package/DOCS/PATTERNS.md +114 -0
- package/DOCS/PATTERNS_AND_TYPED_VALUES.md +665 -0
- package/DOCS/REPL.md +127 -126
- package/DOCS/TEXTUAL_VALUES.md +108 -0
- package/DOCS/TYPE_DERIVATION.md +230 -0
- package/DOCS/book/06-values-in-memory.md +1085 -0
- package/DOCS/book/07-the-partial-function-abi.md +143 -0
- package/DOCS/book/08-operational-semantics-and-execution.md +201 -0
- package/DOCS/book/09-compiler-architecture.md +160 -0
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +167 -0
- package/DOCS/book/14-canonical-serialization.md +176 -0
- package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +155 -0
- package/DOCS/book/overview.txt +68 -0
- package/README.md +78 -30
- package/UU/ta.k +1 -0
- package/UU/ta.k~ +0 -0
- package/UU/tb.k +0 -0
- package/UU/tc.k +0 -0
- package/codecs/README.md +12 -0
- package/codecs/pandoc.css +71 -0
- package/codecs/runtime/test-codec.mjs +89 -0
- package/core.klib +0 -0
- package/core.klib~ +0 -0
- package/ieee.klib +0 -0
- package/kkk.k +197 -0
- package/kkk.klib +0 -0
- package/kkk.klib~ +0 -0
- package/object.mjs +162 -8
- package/objects/README.md +10 -0
- package/objects/compile-lib.mjs +26 -2
- package/objects/compile.mjs +26 -2
- package/objects/decompile.mjs +25 -2
- package/objects/extract-aliases.mjs +59 -0
- package/package.json +3 -2
- package/{codecs/k-pattern.mjs → patterns/from-k.mjs} +3 -3
- package/repl2.mjs +345 -83
- package/scripts/generate-dependency-graph.mjs +121 -0
- package/test-k-object.mjs +77 -1
- package/test-repl2.mjs +65 -8
- package/DOCS/book-combined.html +0 -3798
- package/DOCS/book-combined.md +0 -3745
- package/DOCS/book-combined.pdf +0 -0
- package/DOCS/book-combined.tex +0 -5682
- package/DOCS/book.html +0 -65
- package/DOCS/book.pdf +0 -0
- package/DOCS/book.tex +0 -150
package/DOCS/book-combined.html
DELETED
|
@@ -1,3798 +0,0 @@
|
|
|
1
|
-
<div data-align="center">
|
|
2
|
-
<pre><code> { } { }
|
|
3
|
-
/ \ {.lang name} |
|
|
4
|
-
lang by --> name
|
|
5
|
-
| | |
|
|
6
|
-
'k' 'wojtek' 'k'</code></pre>
|
|
7
|
-
</div>
|
|
8
|
-
<h1 id="table-of-contents">Table of Contents</h1>
|
|
9
|
-
<ol type="1">
|
|
10
|
-
<li><a href="#chapter-1-introduction">Introduction</a></li>
|
|
11
|
-
<li><a href="#chapter-2-syntax-and-values">Syntax and Values</a></li>
|
|
12
|
-
<li><a href="#chapter-3-types-as-finite-automata">Types as Finite
|
|
13
|
-
Automata</a></li>
|
|
14
|
-
<li><a href="#chapter-4-partial-functions-and-composition">Partial
|
|
15
|
-
Functions and Composition</a></li>
|
|
16
|
-
<li><a href="#chapter-5-typing-filters-and-normalization">Typing,
|
|
17
|
-
Filters, and Normalization</a></li>
|
|
18
|
-
<li><a href="#chapter-6-values-in-memory">Values in Memory</a></li>
|
|
19
|
-
<li><a href="#chapter-7-the-partial-function-abi">The Partial Function
|
|
20
|
-
ABI</a></li>
|
|
21
|
-
<li><a href="#chapter-8-operational-semantics-and-execution">Operational
|
|
22
|
-
Semantics and Execution</a></li>
|
|
23
|
-
<li><a href="#chapter-9-compiler-architecture">Compiler
|
|
24
|
-
Architecture</a></li>
|
|
25
|
-
<li><a href="#chapter-10-from-ast-to-intermediate-representation">From
|
|
26
|
-
AST to Intermediate Representation</a></li>
|
|
27
|
-
<li><a href="#chapter-11-llvm-basics">LLVM Basics</a></li>
|
|
28
|
-
<li><a href="#chapter-12-code-generation">Code Generation</a></li>
|
|
29
|
-
<li><a href="#chapter-13-linking-and-execution">Linking and
|
|
30
|
-
Execution</a></li>
|
|
31
|
-
<li><a href="#chapter-14-canonical-serialization">Canonical
|
|
32
|
-
Serialization</a></li>
|
|
33
|
-
<li><a href="#chapter-15-optimization-and-folding">Optimization and
|
|
34
|
-
Folding</a></li>
|
|
35
|
-
<li><a href="#chapter-16-toward-a-universal-schema-registry">Toward a
|
|
36
|
-
Universal Schema Registry</a></li>
|
|
37
|
-
</ol>
|
|
38
|
-
<h2 id="appendices">Appendices</h2>
|
|
39
|
-
<ul>
|
|
40
|
-
<li><a
|
|
41
|
-
href="#appendix-a-implementing-a-prototype-compiler-in-python">Appendix
|
|
42
|
-
A: Implementing a Prototype Compiler in Python</a></li>
|
|
43
|
-
<li><a
|
|
44
|
-
href="#appendix-b-incorporating-external-predefined-types-and-functions">Appendix
|
|
45
|
-
B: Incorporating External Predefined Types and Functions</a></li>
|
|
46
|
-
</ul>
|
|
47
|
-
<hr />
|
|
48
|
-
<h1 id="chapter-1-introduction">Chapter 1 — Introduction</h1>
|
|
49
|
-
<h2 id="the-purpose-of-this-book"><strong>1.1 The purpose of this
|
|
50
|
-
book</strong></h2>
|
|
51
|
-
<p>This book describes a small programming language called
|
|
52
|
-
<strong>k</strong>. It is meant to show how data can be represented and
|
|
53
|
-
transformed in a uniform, precise way.</p>
|
|
54
|
-
<hr />
|
|
55
|
-
<h2 id="data-as-trees"><strong>1.2 Data as trees</strong></h2>
|
|
56
|
-
<p>All information in <code>k</code> is treated as a
|
|
57
|
-
<strong>tree</strong>. A tree has:</p>
|
|
58
|
-
<ul>
|
|
59
|
-
<li>a single root,</li>
|
|
60
|
-
<li>labeled edges (field names or tags),</li>
|
|
61
|
-
<li>and possibly subtrees.</li>
|
|
62
|
-
</ul>
|
|
63
|
-
<p>Both JSON objects and XML documents are trees in this sense. Every
|
|
64
|
-
<code>k</code> value is such a finite labeled tree.</p>
|
|
65
|
-
<hr />
|
|
66
|
-
<h2 id="functions-that-may-fail"><strong>1.3 Functions that may
|
|
67
|
-
fail</strong></h2>
|
|
68
|
-
<p>In ordinary mathematics a function always returns a result. In
|
|
69
|
-
<code>k</code>, a function may be <strong>undefined</strong> for some
|
|
70
|
-
inputs. For example, asking for the field <code>age</code> in a record
|
|
71
|
-
that has no <code>age</code> is undefined.</p>
|
|
72
|
-
<p>We call such mappings <strong>partial functions</strong>.</p>
|
|
73
|
-
<hr />
|
|
74
|
-
<h2 id="simplicity-over-features"><strong>1.4 Simplicity over
|
|
75
|
-
features</strong></h2>
|
|
76
|
-
<p><code>k</code> avoids most language constructs: no <em>variables</em>
|
|
77
|
-
and no <em>control statements</em>. It has only:</p>
|
|
78
|
-
<ol type="1">
|
|
79
|
-
<li><strong>types</strong> (which describe tree shapes), and</li>
|
|
80
|
-
<li><strong>partial functions</strong> (which transform one tree into
|
|
81
|
-
another).</li>
|
|
82
|
-
</ol>
|
|
83
|
-
<p>These two ingredients are sufficient and powerful enough to express
|
|
84
|
-
structured computation in a concise and understandable way.</p>
|
|
85
|
-
<p>There is another concept in the language, called
|
|
86
|
-
<strong>filters</strong>. Filters play a role in the process of
|
|
87
|
-
reasoning about types of partial functions. Filters have been added to
|
|
88
|
-
the syntax of the language as they allow explicit annotations of
|
|
89
|
-
“polymorphic” expressions, i.e., expressions which make sense in
|
|
90
|
-
different contexts. Filters are similar to <em>type classes</em> in
|
|
91
|
-
other languages.</p>
|
|
92
|
-
<hr />
|
|
93
|
-
<hr />
|
|
94
|
-
<h1 id="chapter-2-syntax-and-values">Chapter 2 — Syntax and Values</h1>
|
|
95
|
-
<h2 id="language-fragments"><strong>2.1 Language fragments</strong></h2>
|
|
96
|
-
<p>The <code>k</code> language has only one kind of program element: a
|
|
97
|
-
<strong>definition</strong>. A program is a sequence of definitions of
|
|
98
|
-
two kinds:</p>
|
|
99
|
-
<pre class="k-lang"><code>$ type_name = ...type_expression... ;
|
|
100
|
-
function_name = ...expression... ;</code></pre>
|
|
101
|
-
<p>The definitions are followed in the file by the <em>main
|
|
102
|
-
expression</em>; it represents the partial function defined by the
|
|
103
|
-
program as a whole.</p>
|
|
104
|
-
<p>There is no syntax for values. Every syntactic form in an expression
|
|
105
|
-
describes a <strong>function</strong> – possibly a constant function
|
|
106
|
-
that always returns the same value.</p>
|
|
107
|
-
<hr />
|
|
108
|
-
<h2 id="types"><strong>2.2 Types</strong></h2>
|
|
109
|
-
<p>A type describes the possible <strong>tree shapes</strong> of values.
|
|
110
|
-
Types are formed from two constructors:</p>
|
|
111
|
-
<ol type="1">
|
|
112
|
-
<li><p><strong>Product</strong> – written
|
|
113
|
-
<code>{ T₁ l₁, T₂ l₂, … }</code> represents records with fixed labeled
|
|
114
|
-
fields.</p></li>
|
|
115
|
-
<li><p><strong>Union</strong> – written
|
|
116
|
-
<code>< T₁ l₁, T₂ l₂, … ></code> represents a choice between
|
|
117
|
-
labeled alternatives.</p></li>
|
|
118
|
-
</ol>
|
|
119
|
-
<p>Both are finite and fully explicit. Every type denotes a finite tree
|
|
120
|
-
automaton whose accepted trees are the possible values of that type.</p>
|
|
121
|
-
<hr />
|
|
122
|
-
<h2 id="special-and-limiting-cases"><strong>2.3 Special and limiting
|
|
123
|
-
cases</strong></h2>
|
|
124
|
-
<ol type="1">
|
|
125
|
-
<li><p><strong>Empty product</strong> <code>{}</code> has no fields. It
|
|
126
|
-
represents the type that admits exactly one value, called <em>unit</em>.
|
|
127
|
-
There is nothing exceptional about the type and its value; it is simply
|
|
128
|
-
the degenerate case of a product with zero fields.</p></li>
|
|
129
|
-
<li><p><strong>Empty union</strong> <code><></code> has no
|
|
130
|
-
variants. It represents a type with no possible values.</p></li>
|
|
131
|
-
</ol>
|
|
132
|
-
<hr />
|
|
133
|
-
<h2 id="projections"><strong>2.4 Projections</strong></h2>
|
|
134
|
-
<p><strong>Dot</strong> notation, e.g.,</p>
|
|
135
|
-
<pre class="k"><code> . field_name</code></pre>
|
|
136
|
-
<p>is used for extracting the value of a field from a record (product
|
|
137
|
-
type value). <strong>Div</strong> notation, e.g.,</p>
|
|
138
|
-
<pre class="k"><code> / variant_name</code></pre>
|
|
139
|
-
<p>is used for asserting a particular variant of a union and extracting
|
|
140
|
-
its value. Product type <code>{ T₁ l₁, T₂ l₂, … , Tₙ lₙ }</code>
|
|
141
|
-
naturally defines <code>n</code> partial functions:
|
|
142
|
-
<code>.l₁, .l₂, … , .lₙ</code>,<br />
|
|
143
|
-
and union type <code>< T₁ l₁, T₂ l₂, … , Tₙ lₙ ></code> naturally
|
|
144
|
-
defines <code>n</code> partial functions <code>/l₁, /l₂, … , /lₙ</code>.
|
|
145
|
-
Those partial functions are called <strong>projections</strong> and they
|
|
146
|
-
constitute the basis for the definition of all other partial functions
|
|
147
|
-
in the <code>k</code> language.</p>
|
|
148
|
-
<hr />
|
|
149
|
-
<h2 id="functions"><strong>2.5 Functions</strong></h2>
|
|
150
|
-
<p>Expressions combine partial functions using the following
|
|
151
|
-
operators:</p>
|
|
152
|
-
<ol type="1">
|
|
153
|
-
<li><strong>Composition</strong> <code>(f₁ f₂ …)</code> — sequential
|
|
154
|
-
application.</li>
|
|
155
|
-
<li><strong>Union</strong> <code>< f₁, f₂, … ></code> — try each
|
|
156
|
-
in order, first defined wins.</li>
|
|
157
|
-
<li><strong>Product (parallel)</strong> <code>{ f₁ l₁, f₂ l₂, … }</code>
|
|
158
|
-
— apply all to the same input, succeed only if all succeed.</li>
|
|
159
|
-
<li><strong>Variant construction</strong> <code>| tag</code> — lift the
|
|
160
|
-
input as a variant <code>tag</code> of a union type.</li>
|
|
161
|
-
</ol>
|
|
162
|
-
<p>Parentheses around a composition may be omitted except for the empty
|
|
163
|
-
composition <code>()</code> — the identity function. Empty product,
|
|
164
|
-
<code>{ }</code>, defines a constant function (ignoring its input)
|
|
165
|
-
returning <em>unit</em>.</p>
|
|
166
|
-
<p>It is important to notice that after the three markers:
|
|
167
|
-
<code>dot (.)</code>, <code>div (/)</code>, or <code>pipe (|)</code>,
|
|
168
|
-
there must be a constant label literal. For that reason, it is possible
|
|
169
|
-
and advised not to leave any blanks after the marker, e.g.:</p>
|
|
170
|
-
<pre class="k-lang"><code> .field /'a-tag' |"strange and long tag name ✅" </code></pre>
|
|
171
|
-
<hr />
|
|
172
|
-
<h2 id="example"><strong>2.6 Example</strong></h2>
|
|
173
|
-
<pre class="k-lang"><code>$ bool = < {} true, {} false >;
|
|
174
|
-
true = {} |true $ bool;
|
|
175
|
-
false = {} |false $ bool;
|
|
176
|
-
neg = $ bool < /true false, /false true >;</code></pre>
|
|
177
|
-
<p>This defines a “two-variant” union type and three functions: two
|
|
178
|
-
constants and one transformation exchanging the variants.</p>
|
|
179
|
-
<hr />
|
|
180
|
-
<h2 id="summary"><strong>2.7 Summary</strong></h2>
|
|
181
|
-
<ul>
|
|
182
|
-
<li>All types describe tree shapes.</li>
|
|
183
|
-
<li>As type expression, <code>{}</code> is the empty product type (with
|
|
184
|
-
one value, called <em>unit</em>).</li>
|
|
185
|
-
<li>Functions, not values, are the only expressions in
|
|
186
|
-
<code>k</code>.</li>
|
|
187
|
-
</ul>
|
|
188
|
-
<hr />
|
|
189
|
-
<hr />
|
|
190
|
-
<h1 id="chapter-3-types-as-finite-automata">Chapter 3 — Types as Finite
|
|
191
|
-
Automata</h1>
|
|
192
|
-
<h2 id="motivation"><strong>3.1 Motivation</strong></h2>
|
|
193
|
-
<p>A type in <code>k</code> describes a set of finite labeled trees,
|
|
194
|
-
which can be recognized by a finite tree automaton (FTA). Equivalently,
|
|
195
|
-
a type definition can be seen as a Context-Free Grammar (CFG), where the
|
|
196
|
-
values of the type are the derivation trees of the grammar.</p>
|
|
197
|
-
<p>For example, the recursive type definition of a
|
|
198
|
-
<code>list</code>:</p>
|
|
199
|
-
<pre class="k-lang"><code>$ bool = < {} true, {} false >;
|
|
200
|
-
$ list = < {} nil, { bool head, list tail } cons >;</code></pre>
|
|
201
|
-
<p>corresponds to the following 4-rule grammar:</p>
|
|
202
|
-
<pre class="bnf"><code>1: <bool> ::= {} |true
|
|
203
|
-
2: <bool> ::= {} |false
|
|
204
|
-
3: <list> ::= {} |nil
|
|
205
|
-
4: <list> ::= { <bool> head, <list> tail } |cons</code></pre>
|
|
206
|
-
<p>A value of type <code>list</code> is a derivation tree of this
|
|
207
|
-
grammar. For instance, a list containing a single boolean value
|
|
208
|
-
<code>true</code> can be represented by the following derivation:</p>
|
|
209
|
-
<pre><code><list>
|
|
210
|
-
-- (rule 4) --> { <bool> head, <list> tail } |cons
|
|
211
|
-
| |
|
|
212
|
-
| -- (rule 3) --> {} |nil
|
|
213
|
-
|
|
|
214
|
-
-- (rule 1) --> {} |true</code></pre>
|
|
215
|
-
<p>This derivation tree corresponds to the value generated by constant
|
|
216
|
-
function: <code>{ {} |true head, {} |nil tail } |cons</code>.</p>
|
|
217
|
-
<p>Representing types as automata (or CFGs) provides each type with a
|
|
218
|
-
well-defined structure, independent of the names used in the source
|
|
219
|
-
code. This allows for canonical normal forms and for comparing types for
|
|
220
|
-
equality by structure alone.</p>
|
|
221
|
-
<hr />
|
|
222
|
-
<h2 id="states-and-transitions"><strong>3.2 States and
|
|
223
|
-
Transitions</strong></h2>
|
|
224
|
-
<p>Each type definition introduces one or more <em>states</em> in the
|
|
225
|
-
automaton. A union or a product definition corresponds to a state, and
|
|
226
|
-
the variants or fields correspond to transitions to other states.</p>
|
|
227
|
-
<p>For example, consider the <code>$bool</code> type:</p>
|
|
228
|
-
<pre class="k-lang"><code>$ bool = < {} true, {} false >;</code></pre>
|
|
229
|
-
<p>This definition translates to an automaton with two states:</p>
|
|
230
|
-
<ul>
|
|
231
|
-
<li>A root state, let’s call it <code>C0</code>, representing the
|
|
232
|
-
<code>$bool</code> type itself (a union).</li>
|
|
233
|
-
<li>A state <code>C1</code> representing the empty product
|
|
234
|
-
<code>{}</code>.</li>
|
|
235
|
-
</ul>
|
|
236
|
-
<p>From the root state <code>C0</code>, there are two transitions:</p>
|
|
237
|
-
<ul>
|
|
238
|
-
<li>A transition labeled <code>true</code> to state
|
|
239
|
-
<code>C1</code>.</li>
|
|
240
|
-
<li>A transition labeled <code>false</code> to state
|
|
241
|
-
<code>C1</code>.</li>
|
|
242
|
-
</ul>
|
|
243
|
-
<p><code>C0</code> is the root state of the type, and <code>C1</code> is
|
|
244
|
-
a leaf state, representing an empty value.</p>
|
|
245
|
-
<hr />
|
|
246
|
-
<h2 id="canonical-form"><strong>3.3 Canonical Form</strong></h2>
|
|
247
|
-
<p>Different type expressions can describe the same automaton. For
|
|
248
|
-
example:</p>
|
|
249
|
-
<pre class="k-lang"><code>$ bool = < {} false, {} true >;
|
|
250
|
-
$ pair = { bool x, bool y };
|
|
251
|
-
$ pair2 = { < {} true, {} false > x, bool y };</code></pre>
|
|
252
|
-
<p>The types <code>pair</code> and <code>pair2</code> are structurally
|
|
253
|
-
equivalent because <code>$bool</code> is defined as
|
|
254
|
-
<code>< {} true, {} false ></code>, making the definition of
|
|
255
|
-
<code>x</code> in <code>pair2</code> identical to the standalone
|
|
256
|
-
<code>$bool</code> type used in <code>pair</code>. Canonicalization is
|
|
257
|
-
the process of removing these superficial differences by erasing local
|
|
258
|
-
names and renumbering states to produce a single stable representation
|
|
259
|
-
for each unique type structure.</p>
|
|
260
|
-
<p>The canonical form is generated by traversing the type’s graph
|
|
261
|
-
structure starting from its root state. The process ensures a unique
|
|
262
|
-
representation by following a consistent ordering:</p>
|
|
263
|
-
<ol type="1">
|
|
264
|
-
<li><strong>Start at the Root</strong>: Assign the number
|
|
265
|
-
<code>C0</code> to the root state of the type.</li>
|
|
266
|
-
<li><strong>Explore Neighbors</strong>: Visit all states reachable from
|
|
267
|
-
<code>C0</code>. Sort the transitions alphabetically by their labels
|
|
268
|
-
(field or variant names) and assign consecutive numbers
|
|
269
|
-
(<code>C1</code>, <code>C2</code>, …) to the destination states in that
|
|
270
|
-
order.</li>
|
|
271
|
-
<li><strong>Iterate</strong>: Move to the next state in the numbered
|
|
272
|
-
sequence (<code>C1</code>, then <code>C2</code>, etc.) and repeat the
|
|
273
|
-
process for any of its neighbors that have not yet been numbered.</li>
|
|
274
|
-
<li><strong>Complete</strong>: Continue until all reachable states have
|
|
275
|
-
been assigned a unique number.</li>
|
|
276
|
-
</ol>
|
|
277
|
-
<p>This traversal produces a unique and deterministic numbering for any
|
|
278
|
-
finite directed graph, ensuring that any two structurally identical
|
|
279
|
-
types will have the exact same canonical representation.</p>
|
|
280
|
-
<hr />
|
|
281
|
-
<h2 id="examples"><strong>3.4 Examples</strong></h2>
|
|
282
|
-
<p>For a type representing binary natural numbers:</p>
|
|
283
|
-
<pre class="k-lang"><code>$ bnat = < bnat 0, bnat 1, {} _ >;</code></pre>
|
|
284
|
-
<p>the canonical form is:</p>
|
|
285
|
-
<pre class="k-lang"><code>$C0 = < C0 "0", C0 "1", C1 "_" >;
|
|
286
|
-
$C1 = {};</code></pre>
|
|
287
|
-
<p>The automaton has two states. <code>C0</code> is a recursive state
|
|
288
|
-
that recognizes sequences of “0”s and “1”s, while <code>C1</code> is the
|
|
289
|
-
terminal state, marked by the “_” transition.</p>
|
|
290
|
-
<hr />
|
|
291
|
-
<h2 id="normalization-process"><strong>3.5 Normalization
|
|
292
|
-
Process</strong></h2>
|
|
293
|
-
<p>When compiling a program, the following steps are taken to normalize
|
|
294
|
-
types:</p>
|
|
295
|
-
<ol type="1">
|
|
296
|
-
<li><strong>Collect</strong>: Gather all type definitions from the
|
|
297
|
-
program.</li>
|
|
298
|
-
<li><strong>Expand</strong>: Recursively replace all named types with
|
|
299
|
-
their underlying definitions until only products and unions remain.</li>
|
|
300
|
-
<li><strong>Deduplicate</strong>: Eliminate duplicate type structures by
|
|
301
|
-
comparing them structurally.</li>
|
|
302
|
-
<li><strong>Canonicalize</strong>: Assign stable state numbers to the
|
|
303
|
-
unique types to produce their canonical text representation.</li>
|
|
304
|
-
</ol>
|
|
305
|
-
<p>This process is deterministic, ensuring that the same type structure
|
|
306
|
-
always produces the exact same canonical form.</p>
|
|
307
|
-
<hr />
|
|
308
|
-
<h2 id="hash-based-naming"><strong>3.6 Hash-Based Naming</strong></h2>
|
|
309
|
-
<p>To create a globally unique and stable identifier for each type, the
|
|
310
|
-
compiler computes a hash of its canonical representation. This hash
|
|
311
|
-
becomes the official, unambiguous name of the type.</p>
|
|
312
|
-
<p>For example:</p>
|
|
313
|
-
<pre class="text"><code>Canonical Form: $C0=<C0"0",C0"1",C1"_">;$C1={}
|
|
314
|
-
↓
|
|
315
|
-
Hash
|
|
316
|
-
↓
|
|
317
|
-
Identifier: @BsAqRMv</code></pre>
|
|
318
|
-
<p>Program objects can then refer to types by their hash-based
|
|
319
|
-
identifiers (prefixed with <code>@</code>) without ambiguity.</p>
|
|
320
|
-
<hr />
|
|
321
|
-
<h2 id="interpretation"><strong>3.7 Interpretation</strong></h2>
|
|
322
|
-
<p>The canonical representation of a type can be interpreted as:</p>
|
|
323
|
-
<ul>
|
|
324
|
-
<li>A finite set of states, <code>C0…Cn</code>.</li>
|
|
325
|
-
<li>Each state is either a product (a record with named fields) or a
|
|
326
|
-
union (a set of variants).</li>
|
|
327
|
-
<li>Transitions between states are labeled with strings (field or
|
|
328
|
-
variant names).</li>
|
|
329
|
-
</ul>
|
|
330
|
-
<p>Every value of a given type is a finite tree that is accepted by this
|
|
331
|
-
automaton.</p>
|
|
332
|
-
<hr />
|
|
333
|
-
<h2 id="summary-1"><strong>3.8 Summary</strong></h2>
|
|
334
|
-
<ul>
|
|
335
|
-
<li>Types in <code>k</code> denote sets of finite, labeled trees.</li>
|
|
336
|
-
<li>Every type can be expressed as a finite tree automaton or a
|
|
337
|
-
context-free grammar.</li>
|
|
338
|
-
<li>The canonical form eliminates naming differences, providing a single
|
|
339
|
-
representation for structurally identical types.</li>
|
|
340
|
-
<li>Hash-based naming gives each unique type a stable and globally
|
|
341
|
-
unique identifier.</li>
|
|
342
|
-
</ul>
|
|
343
|
-
<hr />
|
|
344
|
-
<hr />
|
|
345
|
-
<h1 id="chapter-4-partial-functions-and-composition">Chapter 4 — Partial
|
|
346
|
-
Functions and Composition</h1>
|
|
347
|
-
<h2 id="partial-functions"><strong>4.1 Partial functions</strong></h2>
|
|
348
|
-
<p>A <strong>partial function</strong> is a mapping that may be
|
|
349
|
-
undefined for some inputs. In <code>k</code>, every expression denotes
|
|
350
|
-
such a function. If a function is undefined for a given input, the
|
|
351
|
-
evaluation process halts at that point, producing no result.</p>
|
|
352
|
-
<p>There is no notion of error or exception. Undefined means simply “no
|
|
353
|
-
output”.</p>
|
|
354
|
-
<hr />
|
|
355
|
-
<h2 id="composition"><strong>4.2 Composition</strong></h2>
|
|
356
|
-
<p>Composition combines two or more partial functions sequentially. If
|
|
357
|
-
<code>f</code> and <code>g</code> are functions, <code>(f g)</code>
|
|
358
|
-
means “apply <code>f</code>, then apply <code>g</code> to the
|
|
359
|
-
result”.</p>
|
|
360
|
-
<p>A composition <code>(f g)</code> is defined on a value <code>x</code>
|
|
361
|
-
if and only if:</p>
|
|
362
|
-
<ul>
|
|
363
|
-
<li><code>f</code> is defined on <code>x</code>, and</li>
|
|
364
|
-
<li><code>g</code> is defined on the result of <code>f(x)</code>.</li>
|
|
365
|
-
</ul>
|
|
366
|
-
<p>Otherwise, the composition is undefined.</p>
|
|
367
|
-
<p>Composition is <strong>associative</strong>:</p>
|
|
368
|
-
<pre class="math"><code>(f (g h)) ≡ ((f g) h)</code></pre>
|
|
369
|
-
<p>Therefore, parentheses are unnecessary, except for the special case
|
|
370
|
-
of the <strong>empty composition</strong>, written <code>()</code>,
|
|
371
|
-
which is the identity function:</p>
|
|
372
|
-
<pre class="math"><code>() x = x () = x</code></pre>
|
|
373
|
-
<hr />
|
|
374
|
-
<h2 id="product-composition"><strong>4.3 Product
|
|
375
|
-
composition</strong></h2>
|
|
376
|
-
<p>Product composition creates a function that applies several
|
|
377
|
-
subfunctions in parallel to the same input and gathers their results
|
|
378
|
-
into a product value.</p>
|
|
379
|
-
<p>Syntax:</p>
|
|
380
|
-
<pre class="math"><code>{ f₁ l₁, f₂ l₂, …, fₙ lₙ }</code></pre>
|
|
381
|
-
<p>This expression is defined on an input value if all component
|
|
382
|
-
functions are defined on that input. Its result is a product with fields
|
|
383
|
-
labeled <code>l₁ … lₙ</code>, each containing the result of the
|
|
384
|
-
corresponding function.</p>
|
|
385
|
-
<hr />
|
|
386
|
-
<h2 id="union-composition"><strong>4.4 Union composition</strong></h2>
|
|
387
|
-
<p>Union composition represents concurrent evaluation with fallback:</p>
|
|
388
|
-
<pre class="k-lang"><code>< f₁, f₂, …, fₙ ></code></pre>
|
|
389
|
-
<p>The result is defined for an input <code>x</code> if at least one
|
|
390
|
-
subfunction is defined. Evaluation proceeds left to right; the first
|
|
391
|
-
defined result is used. If none are defined, the result is
|
|
392
|
-
undefined.</p>
|
|
393
|
-
<p>Example:</p>
|
|
394
|
-
<pre class="k-lang"><code>< /x, /y ></code></pre>
|
|
395
|
-
<p>extracts variant <code>x</code> if present; otherwise <code>y</code>
|
|
396
|
-
if present.</p>
|
|
397
|
-
<hr />
|
|
398
|
-
<h2 id="constants"><strong>4.5 Constants</strong></h2>
|
|
399
|
-
<p>A constant function is one that always returns the same value,
|
|
400
|
-
regardless of its input. Since <code>k</code> lacks a direct syntax for
|
|
401
|
-
literal values, constants are created using functions that produce
|
|
402
|
-
them.</p>
|
|
403
|
-
<p>For example, we can define functions that return <code>true</code>
|
|
404
|
-
and <code>false</code>:</p>
|
|
405
|
-
<pre class="k-lang"><code>$ bool = < {} true, {} false >;
|
|
406
|
-
true_bool = {} |true $bool ;
|
|
407
|
-
false_bool = {} |false $bool ;</code></pre>
|
|
408
|
-
<p>Here, <code>true_bool</code> and <code>false_bool</code> are constant
|
|
409
|
-
functions. They are also <strong>total functions</strong>, meaning they
|
|
410
|
-
are defined for all inputs. Each function ignores its input and produces
|
|
411
|
-
a fixed boolean value.</p>
|
|
412
|
-
<hr />
|
|
413
|
-
<h2 id="projection-and-variant-value-constructor"><strong>4.6 Projection
|
|
414
|
-
and Variant Value constructor</strong></h2>
|
|
415
|
-
<p>Projection selects a field or a variant from a product or union. It
|
|
416
|
-
is written with a leading dot <code>.</code> or a leading slash
|
|
417
|
-
<code>/</code>, respectively:</p>
|
|
418
|
-
<pre class="k-lang"><code>.x // Selects field 'x' from a product: { T x, ... }
|
|
419
|
-
/x // Extracts the value from a union variant 'x': < T x, ... ></code></pre>
|
|
420
|
-
<p>If the input is a product, <code>.x</code> returns the value of field
|
|
421
|
-
<code>x</code>. If the input is a union, <code>/x</code> returns the
|
|
422
|
-
value of variant <code>x</code>. In all other cases, the projection is
|
|
423
|
-
undefined.</p>
|
|
424
|
-
<p>Variant value constructors for a given union type
|
|
425
|
-
<code>T = <T₁ tag₁, T₂ tag₂, … ></code> are written as
|
|
426
|
-
<code>|tag₁</code>, <code>|tag₂</code>, ….</p>
|
|
427
|
-
<pre class="k-lang"><code>|tag₁ // lift a value of type T₁ into a value of type T</code></pre>
|
|
428
|
-
<p>Projections and variant constructors are the most basic partial
|
|
429
|
-
functions.</p>
|
|
430
|
-
<hr />
|
|
431
|
-
<h2 id="derived-combinations"><strong>4.7 Derived
|
|
432
|
-
combinations</strong></h2>
|
|
433
|
-
<p>Complex functions are built by nesting compositions. For example:</p>
|
|
434
|
-
<pre class="k-lang"><code>{ .x field1, .y |tag field2 }</code></pre>
|
|
435
|
-
<hr />
|
|
436
|
-
<h2 id="identity-and-emptiness"><strong>4.8 Identity and
|
|
437
|
-
emptiness</strong></h2>
|
|
438
|
-
<p>The empty composition <code>()</code> is the identity function. The
|
|
439
|
-
empty union <code><></code> is the always-undefined function. The
|
|
440
|
-
empty product <code>{}</code> is the constant function returning the
|
|
441
|
-
unit value.</p>
|
|
442
|
-
<hr />
|
|
443
|
-
<h2 id="summary-2"><strong>4.9 Summary</strong></h2>
|
|
444
|
-
<ul>
|
|
445
|
-
<li>In <code>k</code>, all expressions denote <strong>partial
|
|
446
|
-
functions</strong>.</li>
|
|
447
|
-
<li>An undefined result simply means “no output,” not an error.</li>
|
|
448
|
-
<li><strong>Composition</strong> <code>(f g)</code> applies functions
|
|
449
|
-
sequentially and is associative, so parentheses are often optional.</li>
|
|
450
|
-
<li>The empty composition <code>()</code> is the <strong>identity
|
|
451
|
-
function</strong>.</li>
|
|
452
|
-
<li><strong>Product composition</strong> <code>{...}</code> runs
|
|
453
|
-
functions in parallel and gathers their results.</li>
|
|
454
|
-
<li><strong>Union composition</strong> <code><...></code> tries
|
|
455
|
-
functions in order, returning the first successful result.</li>
|
|
456
|
-
<li><strong>Projections</strong> (<code>.x</code>, <code>/x</code>) are
|
|
457
|
-
fundamental building blocks for accessing data structures.</li>
|
|
458
|
-
<li><strong>Variant constructor</strong> (<code>|tag</code>) allows
|
|
459
|
-
lifting a value into a variant type value.</li>
|
|
460
|
-
</ul>
|
|
461
|
-
<hr />
|
|
462
|
-
<hr />
|
|
463
|
-
<h1 id="chapter-5-typing-filters-and-normalization">Chapter 5 — Typing,
|
|
464
|
-
Filters, and Normalization</h1>
|
|
465
|
-
<h2 id="types-as-functions"><strong>5.1 Types as functions</strong></h2>
|
|
466
|
-
<p>A type expression in <code>k</code> can appear wherever a function is
|
|
467
|
-
expected. When used this way, it is prefixed by <code>$</code>. It then
|
|
468
|
-
behaves as a partial <strong>identity</strong> function that is defined
|
|
469
|
-
only for values of that type. For example, <code>$ bool</code> is a
|
|
470
|
-
partial identity: it returns its argument unchanged when the argument is
|
|
471
|
-
of type <code>bool</code>, and it is undefined otherwise.</p>
|
|
472
|
-
<p>This convention eliminates any special syntax for annotating
|
|
473
|
-
sub-expressions with types. An expression may be <em>restricted</em> to
|
|
474
|
-
a type simply by composing it with the corresponding type
|
|
475
|
-
expression.</p>
|
|
476
|
-
<hr />
|
|
477
|
-
<h2 id="filters"><strong>5.2 Filters</strong></h2>
|
|
478
|
-
<p>A <strong>filter</strong> is a syntactic form that denotes a
|
|
479
|
-
<em>class of types</em> — a set of types that share a common
|
|
480
|
-
structure.</p>
|
|
481
|
-
<p>Filter expressions are introduced by <code>?</code> and can be:</p>
|
|
482
|
-
<ul>
|
|
483
|
-
<li><strong>Type expressions</strong> — <code>? $bool</code>,
|
|
484
|
-
<code>? $< {} x, bool y ></code></li>
|
|
485
|
-
<li><strong>Product filters</strong> —
|
|
486
|
-
<code>? { Filter1 field1, Filter2 field2 }</code><br />
|
|
487
|
-
</li>
|
|
488
|
-
<li><strong>Union filters</strong> —
|
|
489
|
-
<code>? < Filter1 tag1, Filter2 tag2 ></code></li>
|
|
490
|
-
<li><strong>Product-or-union filters</strong> —
|
|
491
|
-
<code>? ( Filter1 label1, Filter2 label2 )</code></li>
|
|
492
|
-
<li><strong>Filter variables</strong> — <code>? X</code> (metavariables
|
|
493
|
-
representing unknown types)</li>
|
|
494
|
-
<li><strong>Filter bindings</strong> —
|
|
495
|
-
<code>? < X f, (...) = Y g, ... > = X</code></li>
|
|
496
|
-
</ul>
|
|
497
|
-
<p>Filters may contain <code>...</code> to indicate that additional
|
|
498
|
-
fields or tags are allowed: <code>? { Filter1 field1, ... }</code>
|
|
499
|
-
matches any product with at least <code>field1</code>.</p>
|
|
500
|
-
<p>The filter <code>? (...)</code> matches any type. The filter
|
|
501
|
-
<code>? {...}</code> matches any product type. The filter
|
|
502
|
-
<code>? <...></code> matches any union type.</p>
|
|
503
|
-
<hr />
|
|
504
|
-
<h2 id="examples-of-filters"><strong>5.3 Examples of
|
|
505
|
-
filters</strong></h2>
|
|
506
|
-
<ul>
|
|
507
|
-
<li><code>?(...)</code> — represents any type.</li>
|
|
508
|
-
<li><code>?()</code> — represents an empty product or empty union.</li>
|
|
509
|
-
<li><code>?< (...) f, (...) g ></code> — represents all union
|
|
510
|
-
types having exactly two variants <code>f</code> and
|
|
511
|
-
<code>g</code>.</li>
|
|
512
|
-
<li><code>?{ X f, X g }</code> — represents all product types with two
|
|
513
|
-
fields <code>f</code> and <code>g</code>, both of the same type.</li>
|
|
514
|
-
</ul>
|
|
515
|
-
<p>A filter constrains where a partial function is defined; it does not
|
|
516
|
-
affect the operational behavior of the function once defined.</p>
|
|
517
|
-
<hr />
|
|
518
|
-
<h2 id="recursive-filters"><strong>5.4 Recursive filters</strong></h2>
|
|
519
|
-
<p>Filters may be recursive. They can describe families of recursive
|
|
520
|
-
types by defining a metavariable in terms of a filter that references
|
|
521
|
-
it.</p>
|
|
522
|
-
<p>Example (list definition):</p>
|
|
523
|
-
<pre class="k-lang"><code>?< {} nil, {X car, Y cdr} cons > = Y</code></pre>
|
|
524
|
-
<p>This filter states that <code>Y</code> is a union type with two
|
|
525
|
-
variants: <code>nil</code> and <code>cons</code>.</p>
|
|
526
|
-
<ul>
|
|
527
|
-
<li>The <code>nil</code> variant holds an empty product
|
|
528
|
-
<code>{}</code>.</li>
|
|
529
|
-
<li>The <code>cons</code> variant is a product with two fields:
|
|
530
|
-
<code>car</code> of some type <code>X</code>, and <code>cdr</code> of
|
|
531
|
-
type <code>Y</code> itself.</li>
|
|
532
|
-
</ul>
|
|
533
|
-
<p>This recursive structure defines a linked list where each element has
|
|
534
|
-
a <code>car</code> (the value) and a <code>cdr</code> (the rest of the
|
|
535
|
-
list). It thus denotes lists of elements of type <code>X</code>.</p>
|
|
536
|
-
<hr />
|
|
537
|
-
<h2 id="type-variables-and-scope"><strong>5.5 Type variables and
|
|
538
|
-
scope</strong></h2>
|
|
539
|
-
<p>A type variable (an identifier, typically starting with an uppercase
|
|
540
|
-
letter) introduced in a filter is visible within the enclosing function
|
|
541
|
-
definition. For example:</p>
|
|
542
|
-
<pre class="k-lang"><code>car = ?< {} nil, {X car, Y cdr} cons > = Y /cons .car ?X;</code></pre>
|
|
543
|
-
<p>Here:</p>
|
|
544
|
-
<ul>
|
|
545
|
-
<li><code>X</code> and <code>Y</code> are type variables.</li>
|
|
546
|
-
<li>The filter <code>?<{}nil,{X car,Y cdr}cons>=Y</code>
|
|
547
|
-
constrains the function <code>car</code> to be defined only on types
|
|
548
|
-
that match the recursive list structure.</li>
|
|
549
|
-
<li>The expression <code>/cons</code> selects the <code>cons</code>
|
|
550
|
-
variant of the union.</li>
|
|
551
|
-
<li>The expression <code>.car</code> accesses the <code>car</code> field
|
|
552
|
-
of a <code>cons</code> variant.</li>
|
|
553
|
-
<li>The final filter <code>?X</code> asserts that the result of the
|
|
554
|
-
field access is of type <code>X</code>, the type of the list’s
|
|
555
|
-
elements.</li>
|
|
556
|
-
</ul>
|
|
557
|
-
<hr />
|
|
558
|
-
<h2 id="type-inference-and-normalization"><strong>5.6 Type inference and
|
|
559
|
-
normalization</strong></h2>
|
|
560
|
-
<p>Every <code>k</code> program can be analyzed to assign an input and
|
|
561
|
-
an output filter to every sub-expression. This process is called type
|
|
562
|
-
inference abd normalization.</p>
|
|
563
|
-
<p>Type inference and normalization proceeds as follows:</p>
|
|
564
|
-
<ol type="1">
|
|
565
|
-
<li>Build a graph of all type references appearing explicitly and
|
|
566
|
-
implicitly in the program.</li>
|
|
567
|
-
<li>Annotate each expression node with a pair of (input filter, output
|
|
568
|
-
filter).</li>
|
|
569
|
-
<li>Replace filters that match a single, concrete type with that type
|
|
570
|
-
expression, adding any newly-discovered types to the graph.</li>
|
|
571
|
-
<li>Repeat until a fixed point is reached and no more changes
|
|
572
|
-
occur.</li>
|
|
573
|
-
<li>Compute canonical forms for all newly introduced types.</li>
|
|
574
|
-
</ol>
|
|
575
|
-
<hr />
|
|
576
|
-
<h2 id="summary-3"><strong>5.7 Summary</strong></h2>
|
|
577
|
-
<ul>
|
|
578
|
-
<li>Type expressions act as identity functions defined on values of that
|
|
579
|
-
type.</li>
|
|
580
|
-
<li>Filters describe sets of types and can constrain where a function is
|
|
581
|
-
defined.</li>
|
|
582
|
-
<li>Filters may be products, unions, or product-or-union forms, and can
|
|
583
|
-
be recursive.</li>
|
|
584
|
-
<li>Variables in filters have definition-level scope.</li>
|
|
585
|
-
<li>Normalization computes explicit input/output filters for every
|
|
586
|
-
expression.</li>
|
|
587
|
-
<li>Filters are used in the normalization and type checking process.
|
|
588
|
-
They are ignored at runtime.</li>
|
|
589
|
-
</ul>
|
|
590
|
-
<hr />
|
|
591
|
-
<hr />
|
|
592
|
-
<h1 id="chapter-6-values-in-memory-and-canonical-serialization">Chapter
|
|
593
|
-
6 — Values in Memory and Canonical Serialization</h1>
|
|
594
|
-
<h2 id="unified-value-representation"><strong>6.1 Unified value
|
|
595
|
-
representation</strong></h2>
|
|
596
|
-
<p>Every <code>k</code> value exists in one of three forms during
|
|
597
|
-
execution:</p>
|
|
598
|
-
<ol type="1">
|
|
599
|
-
<li><strong>Serialized form</strong> — a canonical bit sequence that can
|
|
600
|
-
be stored, transmitted, or passed between processes.</li>
|
|
601
|
-
<li><strong>Lazy (or hybrid) form</strong> — a partially deserialized
|
|
602
|
-
structure that keeps most data in its serialized form until access is
|
|
603
|
-
needed.</li>
|
|
604
|
-
<li><strong>Materialized form</strong> — a fully deserialized tree of
|
|
605
|
-
nodes in memory.</li>
|
|
606
|
-
</ol>
|
|
607
|
-
<p>This unified approach enables programs to operate on serialized
|
|
608
|
-
inputs without unnecessary deserialization, optimizing performance for
|
|
609
|
-
identity operations and partial data access patterns.</p>
|
|
610
|
-
<hr />
|
|
611
|
-
<h2 id="the-kvalue-abstraction"><strong>6.2 The KValue
|
|
612
|
-
abstraction</strong></h2>
|
|
613
|
-
<p>All values are represented by a single abstraction:</p>
|
|
614
|
-
<div class="sourceCode" id="cb26"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KValue <span class="op">{</span></span>
|
|
615
|
-
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> ValueForm <span class="op">{</span></span>
|
|
616
|
-
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> SERIALIZED<span class="op">,</span> <span class="co">// pure bitstream + type info</span></span>
|
|
617
|
-
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> LAZY<span class="op">,</span> <span class="co">// hybrid: some nodes materialized, others serialized</span></span>
|
|
618
|
-
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> MATERIALIZED<span class="op">,</span> <span class="co">// traditional tree structure</span></span>
|
|
619
|
-
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> EXTERNAL <span class="co">// built-in/foreign type with custom handlers</span></span>
|
|
620
|
-
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> form<span class="op">;</span></span>
|
|
621
|
-
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> </span>
|
|
622
|
-
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> <span class="op">{</span></span>
|
|
623
|
-
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
624
|
-
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// canonical bitstream</span></span>
|
|
625
|
-
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type_id<span class="op">;</span> <span class="co">// identifies canonical type</span></span>
|
|
626
|
-
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> serialized<span class="op">;</span></span>
|
|
627
|
-
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a> </span>
|
|
628
|
-
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
629
|
-
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> root<span class="op">;</span> <span class="co">// root of materialized or partially materialized tree</span></span>
|
|
630
|
-
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> materialized<span class="op">;</span></span>
|
|
631
|
-
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a> </span>
|
|
632
|
-
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
633
|
-
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span><span class="op">*</span> data<span class="op">;</span> <span class="co">// opaque external data</span></span>
|
|
634
|
-
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type_id<span class="op">;</span> <span class="co">// external type identifier</span></span>
|
|
635
|
-
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a> ExternalOps<span class="op">*</span> ops<span class="op">;</span> <span class="co">// function pointers for operations</span></span>
|
|
636
|
-
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> external<span class="op">;</span></span>
|
|
637
|
-
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
638
|
-
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
639
|
-
<h3 id="self-delimiting-streams"><strong>6.2.1 Self-delimiting
|
|
640
|
-
streams</strong></h3>
|
|
641
|
-
<p>The canonical encoding is <strong>self-delimiting</strong>, meaning
|
|
642
|
-
each value can be parsed without knowing its length in advance:</p>
|
|
643
|
-
<ul>
|
|
644
|
-
<li><strong>Union nodes</strong>: Fixed-length discriminators define
|
|
645
|
-
clear boundaries</li>
|
|
646
|
-
<li><strong>Product nodes</strong>: Type structure determines field
|
|
647
|
-
count and termination<br />
|
|
648
|
-
</li>
|
|
649
|
-
<li><strong>External data</strong>: Length-prefixed encoding (LEB128 +
|
|
650
|
-
payload)</li>
|
|
651
|
-
<li><strong>Unit values</strong>: Zero bytes consumed</li>
|
|
652
|
-
</ul>
|
|
653
|
-
<p>This enables <strong>streaming evaluation</strong> where programs can
|
|
654
|
-
process data incrementally without buffering entire inputs.</p>
|
|
655
|
-
<hr />
|
|
656
|
-
<h2 id="lazy-node-structure"><strong>6.3 Lazy node
|
|
657
|
-
structure</strong></h2>
|
|
658
|
-
<p>Nodes in lazy values can be in different states of
|
|
659
|
-
materialization:</p>
|
|
660
|
-
<div class="sourceCode" id="cb27"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KNode <span class="op">{</span></span>
|
|
661
|
-
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> state<span class="op">;</span> <span class="co">// canonical type state (C0, C1,…)</span></span>
|
|
662
|
-
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> tag<span class="op">;</span> <span class="co">// variant index, −1 for product</span></span>
|
|
663
|
-
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> arity<span class="op">;</span> <span class="co">// number of children</span></span>
|
|
664
|
-
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a> </span>
|
|
665
|
-
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> NodeState <span class="op">{</span></span>
|
|
666
|
-
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a> SERIALIZED_CHILD<span class="op">,</span> <span class="co">// child exists as bitstream only</span></span>
|
|
667
|
-
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a> MATERIALIZED_CHILD<span class="op">,</span> <span class="co">// child is fully materialized</span></span>
|
|
668
|
-
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a> EXTERNAL_CHILD <span class="co">// child is external/built-in type</span></span>
|
|
669
|
-
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
670
|
-
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a> </span>
|
|
671
|
-
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> KChild <span class="op">{</span></span>
|
|
672
|
-
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
673
|
-
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">enum</span> NodeState state<span class="op">;</span> <span class="co">// which kind of child this is</span></span>
|
|
674
|
-
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> <span class="op">{</span></span>
|
|
675
|
-
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> node<span class="op">;</span> <span class="co">// materialized child</span></span>
|
|
676
|
-
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
677
|
-
<span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// serialized child data</span></span>
|
|
678
|
-
<span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> bit_offset<span class="op">;</span> <span class="co">// position within parent's bitstream</span></span>
|
|
679
|
-
<span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> serialized<span class="op">;</span></span>
|
|
680
|
-
<span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KValue<span class="op">*</span> external<span class="op">;</span> <span class="co">// external child</span></span>
|
|
681
|
-
<span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
682
|
-
<span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
683
|
-
<span id="cb27-24"><a href="#cb27-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> child<span class="op">[];</span></span>
|
|
684
|
-
<span id="cb27-25"><a href="#cb27-25" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
685
|
-
<hr />
|
|
686
|
-
<h2 id="canonical-serialization-format"><strong>6.4 Canonical
|
|
687
|
-
serialization format</strong></h2>
|
|
688
|
-
<p>The serialized form uses a deterministic canonical encoding that
|
|
689
|
-
produces identical bit sequences for structurally identical values,
|
|
690
|
-
extended to support lazy evaluation:</p>
|
|
691
|
-
<h3 id="canonical-encoding-principles"><strong>6.4.0 Canonical encoding
|
|
692
|
-
principles</strong></h3>
|
|
693
|
-
<p>The encoding is based on the canonical finite automaton
|
|
694
|
-
representation of types (Chapter 3):</p>
|
|
695
|
-
<h4 id="fixed-length-union-codes"><strong>Fixed-length union
|
|
696
|
-
codes</strong></h4>
|
|
697
|
-
<p>For each union state with <em>m</em> variants, we use
|
|
698
|
-
<code>k = ceil(log2(m))</code> bits to encode the variant selection:</p>
|
|
699
|
-
<table>
|
|
700
|
-
<thead>
|
|
701
|
-
<tr>
|
|
702
|
-
<th>Variants</th>
|
|
703
|
-
<th>Bits needed</th>
|
|
704
|
-
<th>Example codes</th>
|
|
705
|
-
</tr>
|
|
706
|
-
</thead>
|
|
707
|
-
<tbody>
|
|
708
|
-
<tr>
|
|
709
|
-
<td>2</td>
|
|
710
|
-
<td>1</td>
|
|
711
|
-
<td><code>0</code>, <code>1</code></td>
|
|
712
|
-
</tr>
|
|
713
|
-
<tr>
|
|
714
|
-
<td>3</td>
|
|
715
|
-
<td>2</td>
|
|
716
|
-
<td><code>00</code>, <code>01</code>, <code>10</code></td>
|
|
717
|
-
</tr>
|
|
718
|
-
<tr>
|
|
719
|
-
<td>4</td>
|
|
720
|
-
<td>2</td>
|
|
721
|
-
<td><code>00</code>, <code>01</code>, <code>10</code>,
|
|
722
|
-
<code>11</code></td>
|
|
723
|
-
</tr>
|
|
724
|
-
<tr>
|
|
725
|
-
<td>5-8</td>
|
|
726
|
-
<td>3</td>
|
|
727
|
-
<td><code>000</code> through <code>111</code></td>
|
|
728
|
-
</tr>
|
|
729
|
-
</tbody>
|
|
730
|
-
</table>
|
|
731
|
-
<h4 id="encoding-by-node-type"><strong>Encoding by node
|
|
732
|
-
type</strong></h4>
|
|
733
|
-
<p>Each node in the value tree is encoded based on its automaton
|
|
734
|
-
state:</p>
|
|
735
|
-
<ul>
|
|
736
|
-
<li><strong>Product nodes</strong> — emit no bits, encode children in
|
|
737
|
-
canonical field order (alphabetical)</li>
|
|
738
|
-
<li><strong>Union nodes</strong> — emit fixed-length variant code, then
|
|
739
|
-
encode the selected child<br />
|
|
740
|
-
</li>
|
|
741
|
-
<li><strong>Unit nodes</strong> — emit nothing (arity = 0, no
|
|
742
|
-
children)</li>
|
|
743
|
-
<li><strong>External nodes</strong> — emit type marker + delegate to
|
|
744
|
-
external serializer</li>
|
|
745
|
-
</ul>
|
|
746
|
-
<h4 id="example-natural-numbers"><strong>Example: Natural
|
|
747
|
-
numbers</strong></h4>
|
|
748
|
-
<p>For type <code>bnat</code>, intuitively binary natural numbers
|
|
749
|
-
defined by <code>$bnat = < bnat 0, bnat 1, {} _ ></code>, we
|
|
750
|
-
get</p>
|
|
751
|
-
<pre class="k-repl"><code>--C bnat
|
|
752
|
-
$ @BsAqRMv = < @BsAqRMv 0, @BsAqRMv 1, @KL _ >; -- $C0=<C0"0",C0"1",C1"_"> $C1={};</code></pre>
|
|
753
|
-
<p>The corresponding Context-Free grammar is:</p>
|
|
754
|
-
<pre class="text"><code>// 3 rules for C0, so we need 2 bits to encode the variant choice:
|
|
755
|
-
C0 -> C0 "|0" // encoded by '00'
|
|
756
|
-
C0 -> C0 "|1" // encoded by '01'
|
|
757
|
-
C0 -> C1 "|_" // encoded by '10'
|
|
758
|
-
// 1 rule for C1 so we need zero bits:
|
|
759
|
-
C1 -> '{}'; // encoded by ''</code></pre>
|
|
760
|
-
<ul>
|
|
761
|
-
<li>3 variants require <code>ceil(log2(3)) = 2</code> bits</li>
|
|
762
|
-
<li>Codes: <code>00</code> (0-bit), <code>01</code> (1-bit),
|
|
763
|
-
<code>10</code> (end marker)</li>
|
|
764
|
-
</ul>
|
|
765
|
-
<p>The value <code>{}|_|0|1</code> or in JSON-like notation
|
|
766
|
-
<code>{1:{0:{_:{}}}}</code> (binary 10₂ = decimal 2) encodes as:</p>
|
|
767
|
-
<pre class="text"><code>01 00 10</code></pre>
|
|
768
|
-
<p>This represents the left-most derivation of <code>{}|_|0|1</code>
|
|
769
|
-
from <code>C0</code>.</p>
|
|
770
|
-
<h4 id="prefix-free-property"><strong>Prefix-free property</strong></h4>
|
|
771
|
-
<p>The encoding is <strong>prefix-free</strong>: no valid encoding is a
|
|
772
|
-
prefix of another. This enables:</p>
|
|
773
|
-
<ul>
|
|
774
|
-
<li>Linear-time parsing without backtracking<br />
|
|
775
|
-
</li>
|
|
776
|
-
<li>Efficient <code>skip_field()</code> operations for lazy
|
|
777
|
-
evaluation</li>
|
|
778
|
-
<li>Deterministic decoding from any valid position in the stream</li>
|
|
779
|
-
</ul>
|
|
780
|
-
<h3 id="dag-compression-for-repeated-subtrees"><strong>6.4.1 DAG
|
|
781
|
-
compression for repeated subtrees</strong></h3>
|
|
782
|
-
<p>The canonical serialization can be compressed using <strong>DAG
|
|
783
|
-
(Directed Acyclic Graph) representation</strong> to eliminate duplicate
|
|
784
|
-
subtrees:</p>
|
|
785
|
-
<h4 id="subtree-identification"><strong>Subtree
|
|
786
|
-
identification</strong></h4>
|
|
787
|
-
<p>Each unique subtree is assigned a <strong>node ID</strong> based on
|
|
788
|
-
its canonical hash:</p>
|
|
789
|
-
<pre class="text"><code>hash(node) = hash(state, tag, arity, hash(child_0), hash(child_1), ...)</code></pre>
|
|
790
|
-
<p>Identical subtrees (same structure and content) get the same hash and
|
|
791
|
-
share the same node ID.</p>
|
|
792
|
-
<h4 id="two-pass-encoding"><strong>Two-pass encoding</strong></h4>
|
|
793
|
-
<h5 id="pass-1-collection"><strong>Pass 1: Collection</strong></h5>
|
|
794
|
-
<ul>
|
|
795
|
-
<li>Traverse the value tree and compute hashes for all subtrees</li>
|
|
796
|
-
<li>Build a <strong>node table</strong> mapping
|
|
797
|
-
<code>node_id → (first_occurrence_offset, reference_count)</code></li>
|
|
798
|
-
<li>Subtrees with <code>reference_count > 1</code> are candidates for
|
|
799
|
-
sharing</li>
|
|
800
|
-
</ul>
|
|
801
|
-
<h5 id="pass-2-emission"><strong>Pass 2: Emission</strong></h5>
|
|
802
|
-
<ul>
|
|
803
|
-
<li><strong>First occurrence</strong>: emit the full subtree
|
|
804
|
-
encoding</li>
|
|
805
|
-
<li><strong>Subsequent occurrences</strong>: emit a
|
|
806
|
-
<strong>back-reference</strong> to the node ID</li>
|
|
807
|
-
</ul>
|
|
808
|
-
<h4 id="back-reference-encoding"><strong>Back-reference
|
|
809
|
-
encoding</strong></h4>
|
|
810
|
-
<pre class="text"><code>| Reference Bit (1) | Node ID (variable length) |</code></pre>
|
|
811
|
-
<ul>
|
|
812
|
-
<li><code>0</code> bit indicates normal encoding follows</li>
|
|
813
|
-
<li><code>1</code> bit indicates back-reference follows</li>
|
|
814
|
-
<li>Node ID uses variable-length encoding (e.g., LEB128)</li>
|
|
815
|
-
</ul>
|
|
816
|
-
<h4 id="example-shared-subtrees"><strong>Example: Shared
|
|
817
|
-
subtrees</strong></h4>
|
|
818
|
-
<p>Consider a binary tree with repeated leaf patterns:</p>
|
|
819
|
-
<pre class="k-lang"><code>$tree = < { tree left, tree right } branch, int leaf >;</code></pre>
|
|
820
|
-
<p>Value: A tree corresponding to the structure:
|
|
821
|
-
<code>branch( leaf(42), branch( leaf(42), leaf(17) ) )</code>:</p>
|
|
822
|
-
<p><strong>Without DAG</strong>: Each leaf <code>(42)</code> is encoded
|
|
823
|
-
separately <strong>With DAG</strong>: The <code>(42)</code> subtree is
|
|
824
|
-
encoded once, then referenced</p>
|
|
825
|
-
<p><strong>Encoding sequence</strong>:</p>
|
|
826
|
-
<pre class="text"><code>Node Table:
|
|
827
|
-
N0: 42 (appears 2 times)
|
|
828
|
-
N1: 17 (appears 1 time)
|
|
829
|
-
|
|
830
|
-
Bitstream:
|
|
831
|
-
00 // branch variant
|
|
832
|
-
0 <N0> // first occurrence of value: 42
|
|
833
|
-
00 // branch variant
|
|
834
|
-
1 N0 // back-reference to value: 42
|
|
835
|
-
0 <N1> // {value: 17}</code></pre>
|
|
836
|
-
<h3 id="stream-structure"><strong>6.4.2 Stream structure</strong></h3>
|
|
837
|
-
<pre class="text"><code>| Header (8 bytes) | Node Count (4 bytes) | Node Table | Bitstream |</code></pre>
|
|
838
|
-
<ul>
|
|
839
|
-
<li><strong>Header</strong> — type hash identifying the canonical
|
|
840
|
-
automaton</li>
|
|
841
|
-
<li><strong>Node Count</strong> — number of shared nodes (0 = no DAG
|
|
842
|
-
compression)</li>
|
|
843
|
-
<li><strong>Node Table</strong> —
|
|
844
|
-
<code>[node_id, offset_in_bitstream, size_in_bits]</code> for each
|
|
845
|
-
shared node</li>
|
|
846
|
-
<li><strong>Bitstream</strong> — concatenated prefix-free codes with
|
|
847
|
-
back-references</li>
|
|
848
|
-
</ul>
|
|
849
|
-
<h4 id="node-table-format"><strong>Node table format</strong></h4>
|
|
850
|
-
<p>When DAG compression is used (<code>Node Count > 0</code>):</p>
|
|
851
|
-
<pre class="text"><code>For each shared node:
|
|
852
|
-
| Node ID (4 bytes) | Offset (4 bytes) | Size in bits (4 bytes) |</code></pre>
|
|
853
|
-
<p>This allows the decoder to:</p>
|
|
854
|
-
<ol type="1">
|
|
855
|
-
<li><strong>Random access</strong>: Jump directly to any shared subtree
|
|
856
|
-
definition</li>
|
|
857
|
-
<li><strong>Lazy loading</strong>: Resolve back-references only when
|
|
858
|
-
needed</li>
|
|
859
|
-
<li><strong>Validation</strong>: Verify subtree boundaries during
|
|
860
|
-
parsing</li>
|
|
861
|
-
</ol>
|
|
862
|
-
<h4 id="compression-algorithms"><strong>Compression
|
|
863
|
-
algorithms</strong></h4>
|
|
864
|
-
<p><strong>Greedy sharing</strong>: Share any subtree that appears more
|
|
865
|
-
than once</p>
|
|
866
|
-
<ul>
|
|
867
|
-
<li>Simple to implement</li>
|
|
868
|
-
<li>Good compression for naturally occurring patterns</li>
|
|
869
|
-
</ul>
|
|
870
|
-
<p><strong>Size-based sharing</strong>: Only share subtrees above a
|
|
871
|
-
minimum size threshold</p>
|
|
872
|
-
<ul>
|
|
873
|
-
<li>Avoids overhead of referencing tiny subtrees</li>
|
|
874
|
-
<li>Better compression ratio in practice</li>
|
|
875
|
-
</ul>
|
|
876
|
-
<p><strong>Frequency-weighted sharing</strong>: Prioritize subtrees by
|
|
877
|
-
<code>size × frequency</code></p>
|
|
878
|
-
<ul>
|
|
879
|
-
<li>Optimal compression for space-constrained scenarios</li>
|
|
880
|
-
<li>Requires more sophisticated analysis</li>
|
|
881
|
-
</ul>
|
|
882
|
-
<h4 id="lazy-back-reference-resolution"><strong>Lazy back-reference
|
|
883
|
-
resolution</strong></h4>
|
|
884
|
-
<p>Back-references integrate seamlessly with lazy evaluation:</p>
|
|
885
|
-
<div class="sourceCode" id="cb37"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr resolve_reference<span class="op">(</span>DecoratedPtr backref<span class="op">)</span> <span class="op">{</span></span>
|
|
886
|
-
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a> node_id <span class="op">=</span> read_variable_int<span class="op">(</span>backref<span class="op">.</span>bits<span class="op">,</span> backref<span class="op">.</span>bit_offset<span class="op">);</span></span>
|
|
887
|
-
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a> </span>
|
|
888
|
-
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Look up in node table</span></span>
|
|
889
|
-
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a> node_entry <span class="op">=</span> node_table<span class="op">[</span>node_id<span class="op">];</span></span>
|
|
890
|
-
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a> </span>
|
|
891
|
-
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span>DecoratedPtr<span class="op">)</span> <span class="op">{</span></span>
|
|
892
|
-
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bits <span class="op">=</span> backref<span class="op">.</span>bits<span class="op">,</span></span>
|
|
893
|
-
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bit_offset <span class="op">=</span> node_entry<span class="op">.</span>offset<span class="op">,</span></span>
|
|
894
|
-
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_state <span class="op">=</span> node_entry<span class="op">.</span>type_state<span class="op">,</span></span>
|
|
895
|
-
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ref_count <span class="op">=</span> <span class="dv">1</span></span>
|
|
896
|
-
<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
897
|
-
<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
898
|
-
<p>The decorated pointer model naturally handles back-references as
|
|
899
|
-
lightweight pointer redirections.</p>
|
|
900
|
-
<h4 id="memory-vs.-compression-trade-offs"><strong>Memory
|
|
901
|
-
vs. compression trade-offs</strong></h4>
|
|
902
|
-
<table>
|
|
903
|
-
<thead>
|
|
904
|
-
<tr>
|
|
905
|
-
<th>Strategy</th>
|
|
906
|
-
<th>Memory usage</th>
|
|
907
|
-
<th>Compression ratio</th>
|
|
908
|
-
<th>Decode speed</th>
|
|
909
|
-
</tr>
|
|
910
|
-
</thead>
|
|
911
|
-
<tbody>
|
|
912
|
-
<tr>
|
|
913
|
-
<td>No DAG</td>
|
|
914
|
-
<td>Low</td>
|
|
915
|
-
<td>1.0× (baseline)</td>
|
|
916
|
-
<td>Fastest</td>
|
|
917
|
-
</tr>
|
|
918
|
-
<tr>
|
|
919
|
-
<td>Greedy DAG</td>
|
|
920
|
-
<td>Medium</td>
|
|
921
|
-
<td>2-10×</td>
|
|
922
|
-
<td>Fast</td>
|
|
923
|
-
</tr>
|
|
924
|
-
<tr>
|
|
925
|
-
<td>Optimal DAG</td>
|
|
926
|
-
<td>High</td>
|
|
927
|
-
<td>5-50×</td>
|
|
928
|
-
<td>Medium</td>
|
|
929
|
-
</tr>
|
|
930
|
-
</tbody>
|
|
931
|
-
</table>
|
|
932
|
-
<p>For <strong>streaming applications</strong>: Prefer greedy DAG with
|
|
933
|
-
small node tables For <strong>archival storage</strong>: Use optimal DAG
|
|
934
|
-
compression For <strong>real-time processing</strong>: Skip DAG
|
|
935
|
-
compression entirely</p>
|
|
936
|
-
<h4
|
|
937
|
-
id="compression-example-repeated-data-structures"><strong>Compression
|
|
938
|
-
example: Repeated data structures</strong></h4>
|
|
939
|
-
<p>Consider a list of similar records:</p>
|
|
940
|
-
<pre class="k-lang"><code>$record = { string name, int age, string department };
|
|
941
|
-
$company = < { record head, company tail } cons, {} nil >;</code></pre>
|
|
942
|
-
<p>Value representing 1000 employees where 80% work in
|
|
943
|
-
“Engineering”:</p>
|
|
944
|
-
<pre class="text"><code>Without DAG: Each "Engineering" string encoded separately
|
|
945
|
-
- 1000 records × 30 bytes/record = 30KB
|
|
946
|
-
|
|
947
|
-
With DAG: "Engineering" string shared via back-references
|
|
948
|
-
- 1 × "Engineering" (11 bytes) + 800 × back-reference (3 bytes) = 2.4KB
|
|
949
|
-
- Compression ratio: ~12.5×</code></pre>
|
|
950
|
-
<p>The DAG representation transforms the <strong>tree</strong> into a
|
|
951
|
-
more efficient <strong>directed acyclic graph</strong>:</p>
|
|
952
|
-
<pre class="text"><code>Tree: Record1 → "Engineering"
|
|
953
|
-
Record2 → "Engineering"
|
|
954
|
-
Record3 → "Engineering"
|
|
955
|
-
...
|
|
956
|
-
|
|
957
|
-
DAG: Record1 ↘
|
|
958
|
-
Record2 → Shared("Engineering")
|
|
959
|
-
Record3 ↗
|
|
960
|
-
...</code></pre>
|
|
961
|
-
<h3 id="hardware-optimized-encoding"><strong>6.4.3 Hardware-optimized
|
|
962
|
-
encoding</strong></h3>
|
|
963
|
-
<p>While bit-level precision is theoretically optimal, modern hardware
|
|
964
|
-
operates on <strong>byte-aligned data</strong> using <strong>word-sized
|
|
965
|
-
registers</strong>. A practical encoding must balance compression with
|
|
966
|
-
decode performance.</p>
|
|
967
|
-
<h4 id="register-friendly-union-encoding"><strong>Register-friendly
|
|
968
|
-
union encoding</strong></h4>
|
|
969
|
-
<p>Instead of <code>ceil(log2(m))</code> bits, use <strong>byte-aligned
|
|
970
|
-
codes</strong> optimized for common union sizes:</p>
|
|
971
|
-
<table>
|
|
972
|
-
<thead>
|
|
973
|
-
<tr>
|
|
974
|
-
<th>Union variants</th>
|
|
975
|
-
<th>Theoretical bits</th>
|
|
976
|
-
<th>Hardware-optimized</th>
|
|
977
|
-
</tr>
|
|
978
|
-
</thead>
|
|
979
|
-
<tbody>
|
|
980
|
-
<tr>
|
|
981
|
-
<td>2-3 variants</td>
|
|
982
|
-
<td>1-2 bits</td>
|
|
983
|
-
<td>1 byte (8 bits)</td>
|
|
984
|
-
</tr>
|
|
985
|
-
<tr>
|
|
986
|
-
<td>4-15 variants</td>
|
|
987
|
-
<td>2-4 bits</td>
|
|
988
|
-
<td>1 byte (8 bits)</td>
|
|
989
|
-
</tr>
|
|
990
|
-
<tr>
|
|
991
|
-
<td>16-255 variants</td>
|
|
992
|
-
<td>4-8 bits</td>
|
|
993
|
-
<td>1 byte (8 bits)</td>
|
|
994
|
-
</tr>
|
|
995
|
-
<tr>
|
|
996
|
-
<td>256+ variants</td>
|
|
997
|
-
<td>8+ bits</td>
|
|
998
|
-
<td>2+ bytes (LEB128)</td>
|
|
999
|
-
</tr>
|
|
1000
|
-
</tbody>
|
|
1001
|
-
</table>
|
|
1002
|
-
<p><strong>Rationale</strong>: Single-byte discriminators enable
|
|
1003
|
-
efficient decoding with simple memory loads and bit masking.</p>
|
|
1004
|
-
<h4 id="simd-friendly-data-layout"><strong>SIMD-friendly data
|
|
1005
|
-
layout</strong></h4>
|
|
1006
|
-
<p>Modern CPUs can process multiple bytes simultaneously using
|
|
1007
|
-
<strong>SIMD instructions</strong>. Structure the encoding to leverage
|
|
1008
|
-
this:</p>
|
|
1009
|
-
<div class="sourceCode" id="cb41"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bad: bit-packed discriminators</span></span>
|
|
1010
|
-
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> BitPacked <span class="op">{</span></span>
|
|
1011
|
-
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> discriminators<span class="op">;</span> <span class="co">// 8 × 8-bit = 64 discriminators packed</span></span>
|
|
1012
|
-
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Requires expensive bit extraction</span></span>
|
|
1013
|
-
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
|
1014
|
-
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a></span>
|
|
1015
|
-
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a><span class="co">// Good: byte-aligned discriminators </span></span>
|
|
1016
|
-
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ByteAligned <span class="op">{</span></span>
|
|
1017
|
-
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> discriminators<span class="op">[</span><span class="dv">8</span><span class="op">];</span> <span class="co">// 8 discriminators, SIMD-friendly</span></span>
|
|
1018
|
-
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// Can be processed with single AVX2 instruction</span></span>
|
|
1019
|
-
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1020
|
-
<h4 id="cache-line-aware-field-ordering"><strong>Cache-line aware field
|
|
1021
|
-
ordering</strong></h4>
|
|
1022
|
-
<p>Arrange product fields to minimize <strong>cache misses</strong>:</p>
|
|
1023
|
-
<div class="sourceCode" id="cb42"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Product field layout optimization</span></span>
|
|
1024
|
-
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ProductLayout <span class="op">{</span></span>
|
|
1025
|
-
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> discriminators<span class="op">[</span>N<span class="op">];</span> <span class="co">// All discriminators together (hot data)</span></span>
|
|
1026
|
-
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> padding<span class="op">[</span><span class="dv">64</span> <span class="op">-</span> N <span class="op">%</span> <span class="dv">64</span><span class="op">];</span> <span class="co">// Align to cache line boundary</span></span>
|
|
1027
|
-
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> field_data<span class="op">[];</span> <span class="co">// Field data follows (cold data)</span></span>
|
|
1028
|
-
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1029
|
-
<p>Fields are ordered by <strong>access frequency</strong> rather than
|
|
1030
|
-
alphabetical order:</p>
|
|
1031
|
-
<ul>
|
|
1032
|
-
<li><strong>Hot fields</strong> (frequently accessed): placed
|
|
1033
|
-
first<br />
|
|
1034
|
-
</li>
|
|
1035
|
-
<li><strong>Cold fields</strong> (rarely accessed): placed last</li>
|
|
1036
|
-
<li><strong>Large fields</strong> (arrays, strings): placed at end to
|
|
1037
|
-
avoid cache pollution</li>
|
|
1038
|
-
</ul>
|
|
1039
|
-
<h4 id="word-aligned-pointer-arithmetic"><strong>Word-aligned pointer
|
|
1040
|
-
arithmetic</strong></h4>
|
|
1041
|
-
<p>Replace bit-level navigation with <strong>word-aligned
|
|
1042
|
-
operations</strong>:</p>
|
|
1043
|
-
<div class="sourceCode" id="cb43"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bit-level navigation (slow)</span></span>
|
|
1044
|
-
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_bitwise<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
|
|
1045
|
-
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> bit_offset <span class="op">=</span> ptr<span class="op">.</span>bit_offset<span class="op">;</span></span>
|
|
1046
|
-
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> field_index<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1047
|
-
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a> bit_offset <span class="op">+=</span> extract_field_bit_size<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> bit_offset<span class="op">);</span> <span class="co">// Expensive!</span></span>
|
|
1048
|
-
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1049
|
-
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> bit_offset<span class="op">);</span></span>
|
|
1050
|
-
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
|
1051
|
-
<span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a></span>
|
|
1052
|
-
<span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Word-aligned navigation (fast)</span></span>
|
|
1053
|
-
<span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_wordwise<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
|
|
1054
|
-
<span id="cb43-12"><a href="#cb43-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Convert to byte offset</span></span>
|
|
1055
|
-
<span id="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1056
|
-
<span id="cb43-14"><a href="#cb43-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read field offset table (precomputed during encoding)</span></span>
|
|
1057
|
-
<span id="cb43-15"><a href="#cb43-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)</span>byte_ptr<span class="op">;</span></span>
|
|
1058
|
-
<span id="cb43-16"><a href="#cb43-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offset <span class="op">=</span> offset_table<span class="op">[</span>field_index<span class="op">];</span> <span class="co">// Single memory load</span></span>
|
|
1059
|
-
<span id="cb43-17"><a href="#cb43-17" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1060
|
-
<span id="cb43-18"><a href="#cb43-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr<span class="op">(</span>ptr<span class="op">.</span>bits<span class="op">,</span> field_offset <span class="op"><<</span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Convert back to bits</span></span>
|
|
1061
|
-
<span id="cb43-19"><a href="#cb43-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1062
|
-
<h4 id="cpu-instruction-optimization"><strong>CPU instruction
|
|
1063
|
-
optimization</strong></h4>
|
|
1064
|
-
<p><strong>Branch prediction friendly encoding</strong>:</p>
|
|
1065
|
-
<div class="sourceCode" id="cb44"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Bad: unpredictable branching</span></span>
|
|
1066
|
-
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a><span class="dt">uint8_t</span> discriminator <span class="op">=</span> <span class="op">*</span>byte_ptr<span class="op">++;</span></span>
|
|
1067
|
-
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a><span class="cf">switch</span> <span class="op">(</span>discriminator<span class="op">)</span> <span class="op">{</span></span>
|
|
1068
|
-
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">0</span><span class="op">:</span> handle_variant_0<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
|
|
1069
|
-
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span> handle_variant_1<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
|
|
1070
|
-
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">2</span><span class="op">:</span> handle_variant_2<span class="op">();</span> <span class="cf">break</span><span class="op">;</span></span>
|
|
1071
|
-
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... many cases cause branch misprediction</span></span>
|
|
1072
|
-
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
|
1073
|
-
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a></span>
|
|
1074
|
-
<span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Good: function table dispatch</span></span>
|
|
1075
|
-
<span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="dt">void</span> <span class="op">(*</span>VariantHandler<span class="op">)(</span><span class="dt">uint8_t</span><span class="op">*</span> data<span class="op">);</span></span>
|
|
1076
|
-
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> VariantHandler variant_handlers<span class="op">[</span><span class="dv">256</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span></span>
|
|
1077
|
-
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a> handle_variant_0<span class="op">,</span> handle_variant_1<span class="op">,</span> handle_variant_2<span class="op">,</span> <span class="co">/* ... */</span></span>
|
|
1078
|
-
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
|
1079
|
-
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a></span>
|
|
1080
|
-
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a><span class="dt">uint8_t</span> discriminator <span class="op">=</span> <span class="op">*</span>byte_ptr<span class="op">++;</span></span>
|
|
1081
|
-
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a>variant_handlers<span class="op">[</span>discriminator<span class="op">](</span>byte_ptr<span class="op">);</span> <span class="co">// Single indirect call</span></span></code></pre></div>
|
|
1082
|
-
<p><strong>Prefetch-aware access patterns</strong>:</p>
|
|
1083
|
-
<div class="sourceCode" id="cb45"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Sequential prefetching for product fields</span></span>
|
|
1084
|
-
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> prefetch_product_fields<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> num_fields<span class="op">)</span> <span class="op">{</span></span>
|
|
1085
|
-
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">));</span></span>
|
|
1086
|
-
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1087
|
-
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Prefetch offset table into L1 cache</span></span>
|
|
1088
|
-
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a> __builtin_prefetch<span class="op">(</span>offset_table<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">3</span><span class="op">);</span> <span class="co">// Read, high temporal locality</span></span>
|
|
1089
|
-
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1090
|
-
<span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// Prefetch first few fields</span></span>
|
|
1091
|
-
<span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> min<span class="op">(</span>num_fields<span class="op">,</span> <span class="dv">4</span><span class="op">);</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1092
|
-
<span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset_table<span class="op">[</span>i<span class="op">];</span></span>
|
|
1093
|
-
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a> __builtin_prefetch<span class="op">(</span>field_ptr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">2</span><span class="op">);</span> <span class="co">// Read, medium temporal locality</span></span>
|
|
1094
|
-
<span id="cb45-12"><a href="#cb45-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1095
|
-
<span id="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1096
|
-
<h4 id="memory-bandwidth-optimization"><strong>Memory bandwidth
|
|
1097
|
-
optimization</strong></h4>
|
|
1098
|
-
<p><strong>Streaming-friendly encoding</strong>:</p>
|
|
1099
|
-
<div class="sourceCode" id="cb46"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Structure data for optimal memory bandwidth</span></span>
|
|
1100
|
-
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> StreamLayout <span class="op">{</span></span>
|
|
1101
|
-
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
1102
|
-
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> total_size<span class="op">;</span> <span class="co">// 4 bytes</span></span>
|
|
1103
|
-
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> num_fields<span class="op">;</span> <span class="co">// 2 bytes </span></span>
|
|
1104
|
-
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> flags<span class="op">;</span> <span class="co">// 2 bytes (padding + metadata)</span></span>
|
|
1105
|
-
<span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> header<span class="op">;</span> <span class="co">// 8 bytes total (fits in single cache line)</span></span>
|
|
1106
|
-
<span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1107
|
-
<span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offsets<span class="op">[];</span> <span class="co">// 4N bytes (word-aligned)</span></span>
|
|
1108
|
-
<span id="cb46-10"><a href="#cb46-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> field_data<span class="op">[];</span> <span class="co">// Variable length data</span></span>
|
|
1109
|
-
<span id="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1110
|
-
<p><strong>Memory access patterns</strong>:</p>
|
|
1111
|
-
<ul>
|
|
1112
|
-
<li><strong>Sequential reads</strong>: Optimal for streaming
|
|
1113
|
-
workloads</li>
|
|
1114
|
-
<li><strong>Random access</strong>: Offset table enables O(1) field
|
|
1115
|
-
access</li>
|
|
1116
|
-
<li><strong>Bulk operations</strong>: SIMD can process multiple
|
|
1117
|
-
discriminators simultaneously</li>
|
|
1118
|
-
</ul>
|
|
1119
|
-
<h4 id="hardware-specific-optimizations"><strong>Hardware-specific
|
|
1120
|
-
optimizations</strong></h4>
|
|
1121
|
-
<p><strong>x86-64 optimizations</strong>:</p>
|
|
1122
|
-
<div class="sourceCode" id="cb47"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Exploit x86-64 addressing modes</span></span>
|
|
1123
|
-
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_x86<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
|
|
1124
|
-
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">));</span></span>
|
|
1125
|
-
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1126
|
-
<span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Single instruction: LEA + memory operand</span></span>
|
|
1127
|
-
<span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset_table<span class="op">[</span>field_index<span class="op">];</span></span>
|
|
1128
|
-
<span id="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1129
|
-
<span id="cb47-8"><a href="#cb47-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
|
|
1130
|
-
<span id="cb47-9"><a href="#cb47-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
|
1131
|
-
<span id="cb47-10"><a href="#cb47-10" aria-hidden="true" tabindex="-1"></a></span>
|
|
1132
|
-
<span id="cb47-11"><a href="#cb47-11" aria-hidden="true" tabindex="-1"></a><span class="co">// Utilize SIMD for bulk discriminator reading</span></span>
|
|
1133
|
-
<span id="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> decode_discriminators_avx2<span class="op">(</span><span class="dt">uint8_t</span><span class="op">*</span> input<span class="op">,</span> <span class="dt">uint8_t</span><span class="op">*</span> output<span class="op">,</span> <span class="dt">size_t</span> count<span class="op">)</span> <span class="op">{</span></span>
|
|
1134
|
-
<span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a> __m256i<span class="op">*</span> input_vec <span class="op">=</span> <span class="op">(</span>__m256i<span class="op">*)</span>input<span class="op">;</span></span>
|
|
1135
|
-
<span id="cb47-14"><a href="#cb47-14" aria-hidden="true" tabindex="-1"></a> __m256i<span class="op">*</span> output_vec <span class="op">=</span> <span class="op">(</span>__m256i<span class="op">*)</span>output<span class="op">;</span></span>
|
|
1136
|
-
<span id="cb47-15"><a href="#cb47-15" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1137
|
-
<span id="cb47-16"><a href="#cb47-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> count <span class="op">/</span> <span class="dv">32</span><span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1138
|
-
<span id="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a> __m256i data <span class="op">=</span> _mm256_load_si256<span class="op">(&</span>input_vec<span class="op">[</span>i<span class="op">]);</span></span>
|
|
1139
|
-
<span id="cb47-18"><a href="#cb47-18" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1140
|
-
<span id="cb47-19"><a href="#cb47-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// Process 32 discriminators in parallel</span></span>
|
|
1141
|
-
<span id="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a> __m256i decoded <span class="op">=</span> _mm256_and_si256<span class="op">(</span>data<span class="op">,</span> _mm256_set1_epi8<span class="op">(</span><span class="bn">0x0F</span><span class="op">));</span></span>
|
|
1142
|
-
<span id="cb47-21"><a href="#cb47-21" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1143
|
-
<span id="cb47-22"><a href="#cb47-22" aria-hidden="true" tabindex="-1"></a> _mm256_store_si256<span class="op">(&</span>output_vec<span class="op">[</span>i<span class="op">],</span> decoded<span class="op">);</span></span>
|
|
1144
|
-
<span id="cb47-23"><a href="#cb47-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1145
|
-
<span id="cb47-24"><a href="#cb47-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1146
|
-
<p><strong>ARM64 optimizations</strong>:</p>
|
|
1147
|
-
<div class="sourceCode" id="cb48"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Exploit ARM64 load-with-offset instructions</span></span>
|
|
1148
|
-
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a>DecoratedPtr navigate_arm64<span class="op">(</span>DecoratedPtr ptr<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
|
|
1149
|
-
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span><span class="op">*</span> offset_table <span class="op">=</span> <span class="op">(</span><span class="dt">uint32_t</span><span class="op">*)(</span>ptr<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>ptr<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">));</span></span>
|
|
1150
|
-
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1151
|
-
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// ARM64: single LDR instruction with register offset</span></span>
|
|
1152
|
-
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> offset <span class="op">=</span> offset_table<span class="op">[</span>field_index<span class="op">];</span></span>
|
|
1153
|
-
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> ptr<span class="op">.</span>bits <span class="op">+</span> offset<span class="op">;</span></span>
|
|
1154
|
-
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1155
|
-
<span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
|
|
1156
|
-
<span id="cb48-10"><a href="#cb48-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1157
|
-
<h4
|
|
1158
|
-
id="performance-analysis-hardware-vs.-theoretical-encoding"><strong>Performance
|
|
1159
|
-
analysis: Hardware vs. theoretical encoding</strong></h4>
|
|
1160
|
-
<p><strong>Decoding performance comparison</strong> (cycles per field
|
|
1161
|
-
access):</p>
|
|
1162
|
-
<table>
|
|
1163
|
-
<colgroup>
|
|
1164
|
-
<col style="width: 27%" />
|
|
1165
|
-
<col style="width: 27%" />
|
|
1166
|
-
<col style="width: 23%" />
|
|
1167
|
-
<col style="width: 20%" />
|
|
1168
|
-
</colgroup>
|
|
1169
|
-
<thead>
|
|
1170
|
-
<tr>
|
|
1171
|
-
<th>Encoding strategy</th>
|
|
1172
|
-
<th>Field access cost</th>
|
|
1173
|
-
<th>Cache behavior</th>
|
|
1174
|
-
<th>SIMD support</th>
|
|
1175
|
-
</tr>
|
|
1176
|
-
</thead>
|
|
1177
|
-
<tbody>
|
|
1178
|
-
<tr>
|
|
1179
|
-
<td>Bit-packed optimal</td>
|
|
1180
|
-
<td>50-100 cycles</td>
|
|
1181
|
-
<td>Poor (bit manipulation)</td>
|
|
1182
|
-
<td>No</td>
|
|
1183
|
-
</tr>
|
|
1184
|
-
<tr>
|
|
1185
|
-
<td>Byte-aligned</td>
|
|
1186
|
-
<td>5-15 cycles</td>
|
|
1187
|
-
<td>Good (word loads)</td>
|
|
1188
|
-
<td>Yes</td>
|
|
1189
|
-
</tr>
|
|
1190
|
-
<tr>
|
|
1191
|
-
<td>Word-aligned + offset table</td>
|
|
1192
|
-
<td>2-8 cycles</td>
|
|
1193
|
-
<td>Excellent (prefetchable)</td>
|
|
1194
|
-
<td>Yes</td>
|
|
1195
|
-
</tr>
|
|
1196
|
-
</tbody>
|
|
1197
|
-
</table>
|
|
1198
|
-
<p><strong>Space vs. time trade-offs</strong>:</p>
|
|
1199
|
-
<pre><code>Bit-packed: 100% space efficiency, 10× decode overhead
|
|
1200
|
-
Byte-aligned: 90% space efficiency, 2× decode overhead
|
|
1201
|
-
Word-aligned: 80% space efficiency, 1× decode overhead (baseline)</code></pre>
|
|
1202
|
-
<p><strong>Real-world measurements</strong> (modern x86-64, 3.2GHz):</p>
|
|
1203
|
-
<div class="sourceCode" id="cb50"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Benchmark: Navigate to field in 1000-field product</span></span>
|
|
1204
|
-
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>Bit<span class="op">-</span>manipulation<span class="op">:</span> <span class="dv">2</span><span class="op">,</span><span class="dv">400</span> ns <span class="op">(</span><span class="dv">7</span><span class="op">,</span><span class="dv">680</span> cycles<span class="op">)</span></span>
|
|
1205
|
-
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a>Byte<span class="op">-</span>aligned<span class="op">:</span> <span class="dv">480</span> ns <span class="op">(</span><span class="dv">1</span><span class="op">,</span><span class="dv">536</span> cycles<span class="op">)</span> </span>
|
|
1206
|
-
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>Word<span class="op">-</span>aligned table<span class="op">:</span> <span class="dv">160</span> ns <span class="op">(</span><span class="dv">512</span> cycles<span class="op">)</span></span></code></pre></div>
|
|
1207
|
-
<p>The <strong>offset table approach</strong> provides the best
|
|
1208
|
-
practical performance despite modest space overhead.</p>
|
|
1209
|
-
<h4 id="recommended-encoding-strategy"><strong>Recommended encoding
|
|
1210
|
-
strategy</strong></h4>
|
|
1211
|
-
<p><strong>Hybrid approach</strong> balancing theory and practice:</p>
|
|
1212
|
-
<ol type="1">
|
|
1213
|
-
<li><strong>Small products</strong> (≤8 fields): Byte-aligned, no offset
|
|
1214
|
-
table</li>
|
|
1215
|
-
<li><strong>Medium products</strong> (9-64 fields): Word-aligned with
|
|
1216
|
-
offset table</li>
|
|
1217
|
-
<li><strong>Large products</strong> (65+ fields): Hierarchical offset
|
|
1218
|
-
tables + prefetching</li>
|
|
1219
|
-
<li><strong>Unions</strong>: Single byte discriminator (sufficient for
|
|
1220
|
-
99.9% of real types)</li>
|
|
1221
|
-
</ol>
|
|
1222
|
-
<p><strong>Encoding format</strong>:</p>
|
|
1223
|
-
<div class="sourceCode" id="cb51"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> OptimalEncoding <span class="op">{</span></span>
|
|
1224
|
-
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> type_tag<span class="op">;</span> <span class="co">// 1 byte: product/union/external marker</span></span>
|
|
1225
|
-
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> arity<span class="op">;</span> <span class="co">// 1 byte: number of children (0-255)</span></span>
|
|
1226
|
-
<span id="cb51-4"><a href="#cb51-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint16_t</span> flags<span class="op">;</span> <span class="co">// 2 bytes: compression flags, alignment info</span></span>
|
|
1227
|
-
<span id="cb51-5"><a href="#cb51-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> total_size<span class="op">;</span> <span class="co">// 4 bytes: total size for skipping</span></span>
|
|
1228
|
-
<span id="cb51-6"><a href="#cb51-6" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1229
|
-
<span id="cb51-7"><a href="#cb51-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// For products with >8 fields:</span></span>
|
|
1230
|
-
<span id="cb51-8"><a href="#cb51-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offsets<span class="op">[</span>arity<span class="op">];</span> <span class="co">// 4×N bytes: random access table</span></span>
|
|
1231
|
-
<span id="cb51-9"><a href="#cb51-9" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1232
|
-
<span id="cb51-10"><a href="#cb51-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// Payload data follows</span></span>
|
|
1233
|
-
<span id="cb51-11"><a href="#cb51-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> data<span class="op">[];</span></span>
|
|
1234
|
-
<span id="cb51-12"><a href="#cb51-12" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1235
|
-
<p><strong>Benefits</strong>:</p>
|
|
1236
|
-
<ul>
|
|
1237
|
-
<li><strong>8-byte aligned</strong> structures for optimal memory
|
|
1238
|
-
access</li>
|
|
1239
|
-
<li><strong>Single cache line</strong> headers for small products<br />
|
|
1240
|
-
</li>
|
|
1241
|
-
<li><strong>SIMD-friendly</strong> data layout</li>
|
|
1242
|
-
<li><strong>Prefetch-optimized</strong> for large structures</li>
|
|
1243
|
-
<li><strong>Hardware-agnostic</strong> but optimized for common
|
|
1244
|
-
architectures</li>
|
|
1245
|
-
</ul>
|
|
1246
|
-
<h3 id="external-type-integration"><strong>6.4.4 External type
|
|
1247
|
-
integration</strong></h3>
|
|
1248
|
-
<pre class="text"><code>| External Marker (2 bits) | Type ID | External Data Length | External Data |</code></pre>
|
|
1249
|
-
<p>This allows built-in types (strings, floats, etc.) to be efficiently
|
|
1250
|
-
serialized within <code>k</code> values while maintaining the canonical
|
|
1251
|
-
property.</p>
|
|
1252
|
-
<hr />
|
|
1253
|
-
<h2 id="demand-driven-deserialization"><strong>6.5 Demand-driven
|
|
1254
|
-
deserialization</strong></h2>
|
|
1255
|
-
<p>Operations on values trigger selective deserialization:</p>
|
|
1256
|
-
<h3 id="access-patterns"><strong>6.5.1 Access patterns</strong></h3>
|
|
1257
|
-
<ul>
|
|
1258
|
-
<li><strong>Identity operation <code>()</code></strong> — no
|
|
1259
|
-
deserialization, direct bitstream copy</li>
|
|
1260
|
-
<li><strong>Field access <code>.field</code></strong> — deserialize only
|
|
1261
|
-
the path to the requested field</li>
|
|
1262
|
-
<li><strong>Pattern matching</strong> — deserialize only the
|
|
1263
|
-
discriminator, then the matched branch</li>
|
|
1264
|
-
<li><strong>Full evaluation</strong> — progressive deserialization as
|
|
1265
|
-
computation proceeds</li>
|
|
1266
|
-
</ul>
|
|
1267
|
-
<h3 id="lazy-evaluation-strategy"><strong>6.5.2 Lazy evaluation
|
|
1268
|
-
strategy</strong></h3>
|
|
1269
|
-
<div class="sourceCode" id="cb53"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a>function access_field<span class="op">(</span>value<span class="op">:</span> KValue<span class="op">,</span> field_path<span class="op">:</span> String<span class="op">[]):</span> KValue <span class="op">{</span></span>
|
|
1270
|
-
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>value<span class="op">.</span>form <span class="op">==</span> SERIALIZED<span class="op">)</span> <span class="op">{</span></span>
|
|
1271
|
-
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// Partially deserialize to reach the field</span></span>
|
|
1272
|
-
<span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a> root <span class="op">=</span> deserialize_to_depth<span class="op">(</span>value<span class="op">,</span> field_path<span class="op">.</span>length<span class="op">);</span></span>
|
|
1273
|
-
<span id="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> make_lazy<span class="op">(</span>root<span class="op">,</span> value<span class="op">.</span>serialized<span class="op">.</span>bits<span class="op">);</span></span>
|
|
1274
|
-
<span id="cb53-6"><a href="#cb53-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1275
|
-
<span id="cb53-7"><a href="#cb53-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1276
|
-
<span id="cb53-8"><a href="#cb53-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>value<span class="op">.</span>form <span class="op">==</span> LAZY<span class="op">)</span> <span class="op">{</span></span>
|
|
1277
|
-
<span id="cb53-9"><a href="#cb53-9" aria-hidden="true" tabindex="-1"></a> node <span class="op">=</span> navigate_path<span class="op">(</span>value<span class="op">.</span>lazy<span class="op">.</span>root<span class="op">,</span> field_path<span class="op">);</span></span>
|
|
1278
|
-
<span id="cb53-10"><a href="#cb53-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>state <span class="op">==</span> SERIALIZED_CHILD<span class="op">)</span> <span class="op">{</span></span>
|
|
1279
|
-
<span id="cb53-11"><a href="#cb53-11" aria-hidden="true" tabindex="-1"></a> <span class="co">// Deserialize this child on demand</span></span>
|
|
1280
|
-
<span id="cb53-12"><a href="#cb53-12" aria-hidden="true" tabindex="-1"></a> child_value <span class="op">=</span> deserialize_child<span class="op">(</span>node<span class="op">,</span> field_idx<span class="op">);</span></span>
|
|
1281
|
-
<span id="cb53-13"><a href="#cb53-13" aria-hidden="true" tabindex="-1"></a> node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>state <span class="op">=</span> MATERIALIZED_CHILD<span class="op">;</span></span>
|
|
1282
|
-
<span id="cb53-14"><a href="#cb53-14" aria-hidden="true" tabindex="-1"></a> node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">].</span>node <span class="op">=</span> child_value<span class="op">;</span></span>
|
|
1283
|
-
<span id="cb53-15"><a href="#cb53-15" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1284
|
-
<span id="cb53-16"><a href="#cb53-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">&</span>node<span class="op">.</span>child<span class="op">[</span>field_idx<span class="op">];</span></span>
|
|
1285
|
-
<span id="cb53-17"><a href="#cb53-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1286
|
-
<span id="cb53-18"><a href="#cb53-18" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1287
|
-
<span id="cb53-19"><a href="#cb53-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// Traditional navigation for fully materialized values</span></span>
|
|
1288
|
-
<span id="cb53-20"><a href="#cb53-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> navigate_materialized<span class="op">(</span>value<span class="op">,</span> field_path<span class="op">);</span></span>
|
|
1289
|
-
<span id="cb53-21"><a href="#cb53-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1290
|
-
<hr />
|
|
1291
|
-
<h2 id="external-type-system"><strong>6.6 External type
|
|
1292
|
-
system</strong></h2>
|
|
1293
|
-
<p>Built-in and foreign types integrate through a plugin interface:</p>
|
|
1294
|
-
<h3 id="external-operations"><strong>6.6.1 External
|
|
1295
|
-
operations</strong></h3>
|
|
1296
|
-
<div class="sourceCode" id="cb54"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ExternalOps <span class="op">{</span></span>
|
|
1297
|
-
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a> KValue<span class="op">*</span> <span class="op">(*</span>serialize<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
|
|
1298
|
-
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span><span class="op">*</span> <span class="op">(*</span>deserialize<span class="op">)(</span>KValue<span class="op">*</span> serialized<span class="op">);</span></span>
|
|
1299
|
-
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a> KValue<span class="op">*</span> <span class="op">(*</span>apply_function<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> func_name<span class="op">,</span> KValue<span class="op">*</span> args<span class="op">);</span></span>
|
|
1300
|
-
<span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> <span class="op">(*</span>equals<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> a<span class="op">,</span> <span class="dt">void</span><span class="op">*</span> b<span class="op">);</span></span>
|
|
1301
|
-
<span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> <span class="op">(*</span>hash<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
|
|
1302
|
-
<span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> <span class="op">(*</span>destroy<span class="op">)(</span><span class="dt">void</span><span class="op">*</span> data<span class="op">);</span></span>
|
|
1303
|
-
<span id="cb54-8"><a href="#cb54-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1304
|
-
<h3 id="built-in-type-examples"><strong>6.6.2 Built-in type
|
|
1305
|
-
examples</strong></h3>
|
|
1306
|
-
<ul>
|
|
1307
|
-
<li><strong>Strings</strong> — UTF-8 encoded with length prefix</li>
|
|
1308
|
-
<li><strong>Integers</strong> — variable-length encoding (LEB128)</li>
|
|
1309
|
-
<li><strong>Floats</strong> — IEEE 754 binary representation</li>
|
|
1310
|
-
<li><strong>Blobs</strong> — raw binary data with length prefix</li>
|
|
1311
|
-
<li><strong>Handles</strong> — opaque references to external
|
|
1312
|
-
resources</li>
|
|
1313
|
-
</ul>
|
|
1314
|
-
<h3 id="type-registration"><strong>6.6.3 Type registration</strong></h3>
|
|
1315
|
-
<div class="sourceCode" id="cb55"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> register_external_type<span class="op">(</span><span class="dt">int</span> type_id<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> name<span class="op">,</span> ExternalOps<span class="op">*</span> ops<span class="op">)</span> <span class="op">{</span></span>
|
|
1316
|
-
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a> external_types<span class="op">[</span>type_id<span class="op">]</span> <span class="op">=</span> <span class="op">{</span></span>
|
|
1317
|
-
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>name <span class="op">=</span> name<span class="op">,</span></span>
|
|
1318
|
-
<span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ops <span class="op">=</span> ops<span class="op">,</span></span>
|
|
1319
|
-
<span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>canonical_hash <span class="op">=</span> compute_type_hash<span class="op">(</span>name<span class="op">,</span> ops<span class="op">-></span>signature<span class="op">)</span></span>
|
|
1320
|
-
<span id="cb55-6"><a href="#cb55-6" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
|
1321
|
-
<span id="cb55-7"><a href="#cb55-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1322
|
-
<hr />
|
|
1323
|
-
<h2 id="memory-management-and-performance"><strong>6.7 Memory management
|
|
1324
|
-
and performance</strong></h2>
|
|
1325
|
-
<h3 id="arena-allocation"><strong>6.7.1 Arena allocation</strong></h3>
|
|
1326
|
-
<p>All materialized nodes use arena allocation for fast allocation and
|
|
1327
|
-
bulk deallocation:</p>
|
|
1328
|
-
<div class="sourceCode" id="cb56"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Arena <span class="op">{</span></span>
|
|
1329
|
-
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> memory<span class="op">;</span></span>
|
|
1330
|
-
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> capacity<span class="op">;</span></span>
|
|
1331
|
-
<span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> used<span class="op">;</span></span>
|
|
1332
|
-
<span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a> Arena<span class="op">*</span> next<span class="op">;</span> <span class="co">// linked list of arena blocks</span></span>
|
|
1333
|
-
<span id="cb56-6"><a href="#cb56-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1334
|
-
<h3 id="sharing-and-deduplication"><strong>6.7.2 Sharing and
|
|
1335
|
-
deduplication</strong></h3>
|
|
1336
|
-
<ul>
|
|
1337
|
-
<li><strong>Canonical folding</strong> — identical subtrees share the
|
|
1338
|
-
same materialized nodes</li>
|
|
1339
|
-
<li><strong>Bitstream sharing</strong> — multiple lazy values can
|
|
1340
|
-
reference the same underlying bitstream</li>
|
|
1341
|
-
<li><strong>DAG back-references</strong> — shared subtrees in serialized
|
|
1342
|
-
form avoid duplication during lazy materialization</li>
|
|
1343
|
-
<li><strong>External sharing</strong> — external values use reference
|
|
1344
|
-
counting or garbage collection as appropriate</li>
|
|
1345
|
-
</ul>
|
|
1346
|
-
<h3 id="optimization-opportunities"><strong>6.7.3 Optimization
|
|
1347
|
-
opportunities</strong></h3>
|
|
1348
|
-
<ul>
|
|
1349
|
-
<li><strong>Zero-copy operations</strong> — identity, field projection
|
|
1350
|
-
on serialized values</li>
|
|
1351
|
-
<li><strong>Streaming evaluation</strong> — process large datasets
|
|
1352
|
-
without full materialization<br />
|
|
1353
|
-
</li>
|
|
1354
|
-
<li><strong>Parallel deserialization</strong> — independent subtrees can
|
|
1355
|
-
be materialized concurrently</li>
|
|
1356
|
-
<li><strong>DAG-aware caching</strong> — cache resolutions of frequently
|
|
1357
|
-
accessed back-references</li>
|
|
1358
|
-
<li><strong>Memoization</strong> — cache frequently accessed paths in
|
|
1359
|
-
lazy structures</li>
|
|
1360
|
-
</ul>
|
|
1361
|
-
<hr />
|
|
1362
|
-
<h2 id="example-lazy-evaluation-in-practice"><strong>6.8 Example: Lazy
|
|
1363
|
-
evaluation in practice</strong></h2>
|
|
1364
|
-
<p>Consider processing a large JSON-like structure where we only need
|
|
1365
|
-
one field:</p>
|
|
1366
|
-
<pre class="k-lang"><code>$record = { string name, list data, metadata meta };
|
|
1367
|
-
$list = < {nat value, list next} cons, {} nil >;
|
|
1368
|
-
$metadata = { timestamp created, string author };</code></pre>
|
|
1369
|
-
<p>For the input program <code>\x.x.name</code> (extract name
|
|
1370
|
-
field):</p>
|
|
1371
|
-
<ol type="1">
|
|
1372
|
-
<li><strong>Input</strong> arrives as serialized bitstream (e.g., from
|
|
1373
|
-
network/disk)</li>
|
|
1374
|
-
<li><strong>Lazy parsing</strong> deserializes only the discriminator of
|
|
1375
|
-
the root product</li>
|
|
1376
|
-
<li><strong>Field access</strong> deserializes path to <code>name</code>
|
|
1377
|
-
field, leaving <code>data</code> and <code>meta</code> serialized</li>
|
|
1378
|
-
<li><strong>Output</strong> the extracted string value (possibly in
|
|
1379
|
-
external string format)</li>
|
|
1380
|
-
</ol>
|
|
1381
|
-
<p>The entire <code>data</code> list and <code>metadata</code> remain as
|
|
1382
|
-
untouched bitstreams, providing massive performance benefits for large,
|
|
1383
|
-
sparsely accessed data structures.</p>
|
|
1384
|
-
<h3 id="serialized-representation"><strong>6.8.1 Serialized
|
|
1385
|
-
representation</strong></h3>
|
|
1386
|
-
<p>The same value can exist in different forms simultaneously:</p>
|
|
1387
|
-
<div class="sourceCode" id="cb58"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Original input: fully serialized</span></span>
|
|
1388
|
-
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>KValue input <span class="op">=</span> <span class="op">{</span></span>
|
|
1389
|
-
<span id="cb58-3"><a href="#cb58-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> SERIALIZED<span class="op">,</span></span>
|
|
1390
|
-
<span id="cb58-4"><a href="#cb58-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span></span>
|
|
1391
|
-
<span id="cb58-5"><a href="#cb58-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>bits <span class="op">=</span> bitstream_buffer<span class="op">,</span></span>
|
|
1392
|
-
<span id="cb58-6"><a href="#cb58-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_hash <span class="op">=</span> hash<span class="op">(</span><span class="st">"record"</span><span class="op">)</span></span>
|
|
1393
|
-
<span id="cb58-7"><a href="#cb58-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1394
|
-
<span id="cb58-8"><a href="#cb58-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
|
1395
|
-
<span id="cb58-9"><a href="#cb58-9" aria-hidden="true" tabindex="-1"></a></span>
|
|
1396
|
-
<span id="cb58-10"><a href="#cb58-10" aria-hidden="true" tabindex="-1"></a><span class="co">// After partial access: hybrid lazy</span></span>
|
|
1397
|
-
<span id="cb58-11"><a href="#cb58-11" aria-hidden="true" tabindex="-1"></a>KValue hybrid <span class="op">=</span> <span class="op">{</span></span>
|
|
1398
|
-
<span id="cb58-12"><a href="#cb58-12" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> LAZY<span class="op">,</span></span>
|
|
1399
|
-
<span id="cb58-13"><a href="#cb58-13" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>lazy<span class="op">.</span>root <span class="op">=</span> <span class="op">{</span></span>
|
|
1400
|
-
<span id="cb58-14"><a href="#cb58-14" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>state <span class="op">=</span> <span class="dv">0</span><span class="op">,</span> <span class="op">.</span>tag <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">,</span> <span class="op">.</span>arity <span class="op">=</span> <span class="dv">3</span><span class="op">,</span></span>
|
|
1401
|
-
<span id="cb58-15"><a href="#cb58-15" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>child <span class="op">=</span> <span class="op">{</span></span>
|
|
1402
|
-
<span id="cb58-16"><a href="#cb58-16" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> MATERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>node <span class="op">=</span> materialized_string_node <span class="op">},</span> <span class="co">// name: materialized</span></span>
|
|
1403
|
-
<span id="cb58-17"><a href="#cb58-17" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> SERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span>bits<span class="op">+</span>offset<span class="op">,</span> <span class="dv">64</span><span class="op">}</span> <span class="op">},</span> <span class="co">// data: still serialized </span></span>
|
|
1404
|
-
<span id="cb58-18"><a href="#cb58-18" aria-hidden="true" tabindex="-1"></a> <span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">.</span>state <span class="op">=</span> SERIALIZED_CHILD<span class="op">,</span> <span class="op">.</span>serialized <span class="op">=</span> <span class="op">{</span>bits<span class="op">+</span>offset<span class="op">,</span> <span class="dv">1088</span><span class="op">}</span> <span class="op">}</span> <span class="co">// meta: still serialized</span></span>
|
|
1405
|
-
<span id="cb58-19"><a href="#cb58-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1406
|
-
<span id="cb58-20"><a href="#cb58-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1407
|
-
<span id="cb58-21"><a href="#cb58-21" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1408
|
-
<h3 id="external-type-integration-example"><strong>6.8.2 External type
|
|
1409
|
-
integration example</strong></h3>
|
|
1410
|
-
<div class="sourceCode" id="cb59"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Built-in string type</span></span>
|
|
1411
|
-
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>KValue string_value <span class="op">=</span> <span class="op">{</span></span>
|
|
1412
|
-
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>form <span class="op">=</span> EXTERNAL<span class="op">,</span></span>
|
|
1413
|
-
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>external <span class="op">=</span> <span class="op">{</span></span>
|
|
1414
|
-
<span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>data <span class="op">=</span> utf8_string_data<span class="op">,</span></span>
|
|
1415
|
-
<span id="cb59-6"><a href="#cb59-6" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>type_id <span class="op">=</span> BUILTIN_STRING<span class="op">,</span></span>
|
|
1416
|
-
<span id="cb59-7"><a href="#cb59-7" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>ops <span class="op">=</span> <span class="op">&</span>string_operations</span>
|
|
1417
|
-
<span id="cb59-8"><a href="#cb59-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1418
|
-
<span id="cb59-9"><a href="#cb59-9" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
|
1419
|
-
<span id="cb59-10"><a href="#cb59-10" aria-hidden="true" tabindex="-1"></a></span>
|
|
1420
|
-
<span id="cb59-11"><a href="#cb59-11" aria-hidden="true" tabindex="-1"></a><span class="co">// The string_operations provide:</span></span>
|
|
1421
|
-
<span id="cb59-12"><a href="#cb59-12" aria-hidden="true" tabindex="-1"></a>ExternalOps string_operations <span class="op">=</span> <span class="op">{</span></span>
|
|
1422
|
-
<span id="cb59-13"><a href="#cb59-13" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>serialize <span class="op">=</span> string_to_canonical_bits<span class="op">,</span></span>
|
|
1423
|
-
<span id="cb59-14"><a href="#cb59-14" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>deserialize <span class="op">=</span> canonical_bits_to_string<span class="op">,</span></span>
|
|
1424
|
-
<span id="cb59-15"><a href="#cb59-15" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>apply_function <span class="op">=</span> string_builtin_functions<span class="op">,</span> <span class="co">// length, concat, etc.</span></span>
|
|
1425
|
-
<span id="cb59-16"><a href="#cb59-16" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>equals <span class="op">=</span> utf8_string_compare<span class="op">,</span></span>
|
|
1426
|
-
<span id="cb59-17"><a href="#cb59-17" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>hash <span class="op">=</span> utf8_string_hash<span class="op">,</span></span>
|
|
1427
|
-
<span id="cb59-18"><a href="#cb59-18" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span>destroy <span class="op">=</span> free_string_data</span>
|
|
1428
|
-
<span id="cb59-19"><a href="#cb59-19" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1429
|
-
<hr />
|
|
1430
|
-
<h2 id="summary-4"><strong>6.9 Summary</strong></h2>
|
|
1431
|
-
<p>This unified representation provides several key advantages:</p>
|
|
1432
|
-
<ul>
|
|
1433
|
-
<li><strong>Performance</strong> — avoid unnecessary deserialization
|
|
1434
|
-
through lazy evaluation</li>
|
|
1435
|
-
<li><strong>Memory efficiency</strong> — share serialized data between
|
|
1436
|
-
multiple references</li>
|
|
1437
|
-
<li><strong>Composability</strong> — external types integrate seamlessly
|
|
1438
|
-
with k’s type system</li>
|
|
1439
|
-
<li><strong>Streaming</strong> — process large data structures with
|
|
1440
|
-
bounded memory usage</li>
|
|
1441
|
-
<li><strong>Determinism</strong> — canonical serialization ensures
|
|
1442
|
-
reproducible computation</li>
|
|
1443
|
-
</ul>
|
|
1444
|
-
<p>The design supports the full spectrum from zero-copy identity
|
|
1445
|
-
operations to fully materialized tree traversal, allowing the runtime to
|
|
1446
|
-
automatically choose the most efficient representation for each use
|
|
1447
|
-
case.</p>
|
|
1448
|
-
<h3 id="key-design-principles"><strong>6.9.1 Key design
|
|
1449
|
-
principles</strong></h3>
|
|
1450
|
-
<ul>
|
|
1451
|
-
<li><strong>Immutability</strong> — all representations are immutable,
|
|
1452
|
-
enabling safe sharing</li>
|
|
1453
|
-
<li><strong>Demand-driven</strong> — materialization happens only when
|
|
1454
|
-
computation requires it</li>
|
|
1455
|
-
<li><strong>Canonical</strong> — serialized forms are deterministic and
|
|
1456
|
-
hashable</li>
|
|
1457
|
-
<li><strong>Extensible</strong> — external types extend the system
|
|
1458
|
-
without breaking canonical properties</li>
|
|
1459
|
-
<li><strong>Unified</strong> — single abstraction handles all value
|
|
1460
|
-
representations</li>
|
|
1461
|
-
</ul>
|
|
1462
|
-
<hr />
|
|
1463
|
-
<h2 id="execution-model-with-decorated-pointers"><strong>6.10 Execution
|
|
1464
|
-
model with decorated pointers</strong></h2>
|
|
1465
|
-
<p>The formal execution model is based on decorated pointers, which
|
|
1466
|
-
represent values during execution:</p>
|
|
1467
|
-
<h3 id="decorated-pointers"><strong>6.10.1 Decorated
|
|
1468
|
-
pointers</strong></h3>
|
|
1469
|
-
<p>Every value during execution is represented by a <strong>decorated
|
|
1470
|
-
pointer</strong>:</p>
|
|
1471
|
-
<div class="sourceCode" id="cb60"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> DecoratedPtr <span class="op">{</span></span>
|
|
1472
|
-
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> bits<span class="op">;</span> <span class="co">// pointer into serialized input heap</span></span>
|
|
1473
|
-
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> bit_offset<span class="op">;</span> <span class="co">// bit position within the stream</span></span>
|
|
1474
|
-
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a> TypeState type_state<span class="op">;</span> <span class="co">// canonical automaton state (C0, C1, ...)</span></span>
|
|
1475
|
-
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> ref_count<span class="op">;</span> <span class="co">// for sharing and caching</span></span>
|
|
1476
|
-
<span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
1477
|
-
<span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> is_cached<span class="op">;</span> <span class="co">// memoization flag</span></span>
|
|
1478
|
-
<span id="cb60-8"><a href="#cb60-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint64_t</span> content_hash<span class="op">;</span> <span class="co">// for cache lookup</span></span>
|
|
1479
|
-
<span id="cb60-9"><a href="#cb60-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> cache<span class="op">;</span></span>
|
|
1480
|
-
<span id="cb60-10"><a href="#cb60-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1481
|
-
<p>The key insight: <strong>decorated pointers are lightweight and can
|
|
1482
|
-
be computed without memory allocation</strong>.</p>
|
|
1483
|
-
<h3 id="program-execution-pipeline"><strong>6.10.2 Program execution
|
|
1484
|
-
pipeline</strong></h3>
|
|
1485
|
-
<p>A compiled k program is a composition of operations:
|
|
1486
|
-
<code>projection ∘ product ∘ union ∘ builtin_call ∘ ...</code></p>
|
|
1487
|
-
<p>Each operation transforms a decorated pointer:</p>
|
|
1488
|
-
<pre class="text"><code>DecoratedPtr → DecoratedPtr</code></pre>
|
|
1489
|
-
<h4 id="projection-operation"><strong>Projection operation</strong></h4>
|
|
1490
|
-
<p>For field access <code>.field_name</code>:</p>
|
|
1491
|
-
<div class="sourceCode" id="cb62"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr project_field_optimized<span class="op">(</span>DecoratedPtr input<span class="op">,</span> <span class="dt">int</span> field_index<span class="op">)</span> <span class="op">{</span></span>
|
|
1492
|
-
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Hardware-optimized field navigation</span></span>
|
|
1493
|
-
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> input<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>input<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">);</span></span>
|
|
1494
|
-
<span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1495
|
-
<span id="cb62-5"><a href="#cb62-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read encoding header</span></span>
|
|
1496
|
-
<span id="cb62-6"><a href="#cb62-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> OptimalEncoding<span class="op">*</span> header <span class="op">=</span> <span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">*)</span>byte_ptr<span class="op">;</span></span>
|
|
1497
|
-
<span id="cb62-7"><a href="#cb62-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1498
|
-
<span id="cb62-8"><a href="#cb62-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>header<span class="op">-></span>arity <span class="op"><=</span> <span class="dv">8</span><span class="op">)</span> <span class="op">{</span></span>
|
|
1499
|
-
<span id="cb62-9"><a href="#cb62-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// Small product: sequential scan (cache-friendly)</span></span>
|
|
1500
|
-
<span id="cb62-10"><a href="#cb62-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> field_ptr <span class="op">=</span> byte_ptr <span class="op">+</span> <span class="kw">sizeof</span><span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">);</span></span>
|
|
1501
|
-
<span id="cb62-11"><a href="#cb62-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> field_index<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1502
|
-
<span id="cb62-12"><a href="#cb62-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_size <span class="op">=</span> <span class="op">*(</span><span class="dt">uint32_t</span><span class="op">*)</span>field_ptr<span class="op">;</span> <span class="co">// First 4 bytes = size</span></span>
|
|
1503
|
-
<span id="cb62-13"><a href="#cb62-13" aria-hidden="true" tabindex="-1"></a> field_ptr <span class="op">+=</span> field_size<span class="op">;</span></span>
|
|
1504
|
-
<span id="cb62-14"><a href="#cb62-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1505
|
-
<span id="cb62-15"><a href="#cb62-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>field_ptr<span class="op">);</span></span>
|
|
1506
|
-
<span id="cb62-16"><a href="#cb62-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
|
|
1507
|
-
<span id="cb62-17"><a href="#cb62-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// Large product: offset table lookup (O(1) access)</span></span>
|
|
1508
|
-
<span id="cb62-18"><a href="#cb62-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint32_t</span> field_offset <span class="op">=</span> header<span class="op">-></span>field_offsets<span class="op">[</span>field_index<span class="op">];</span></span>
|
|
1509
|
-
<span id="cb62-19"><a href="#cb62-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>byte_ptr <span class="op">+</span> field_offset<span class="op">);</span></span>
|
|
1510
|
-
<span id="cb62-20"><a href="#cb62-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1511
|
-
<span id="cb62-21"><a href="#cb62-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1512
|
-
<p><strong>Key property</strong>: Hardware-optimized navigation using
|
|
1513
|
-
word-aligned loads and offset tables.</p>
|
|
1514
|
-
<h4 id="union-operation"><strong>Union operation</strong></h4>
|
|
1515
|
-
<p>For pattern matching
|
|
1516
|
-
<code>case { tag1 → ..., tag2 → ... }</code>:</p>
|
|
1517
|
-
<div class="sourceCode" id="cb63"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr match_union_optimized<span class="op">(</span>DecoratedPtr input<span class="op">,</span> <span class="dt">int</span> expected_tag<span class="op">)</span> <span class="op">{</span></span>
|
|
1518
|
-
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Read single-byte discriminator (hardware-friendly)</span></span>
|
|
1519
|
-
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> byte_ptr <span class="op">=</span> input<span class="op">.</span>bits <span class="op">+</span> <span class="op">(</span>input<span class="op">.</span>bit_offset <span class="op">>></span> <span class="dv">3</span><span class="op">);</span></span>
|
|
1520
|
-
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> OptimalEncoding<span class="op">*</span> header <span class="op">=</span> <span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">*)</span>byte_ptr<span class="op">;</span></span>
|
|
1521
|
-
<span id="cb63-5"><a href="#cb63-5" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1522
|
-
<span id="cb63-6"><a href="#cb63-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span> actual_tag <span class="op">=</span> header<span class="op">-></span>data<span class="op">[</span><span class="dv">0</span><span class="op">];</span> <span class="co">// First byte of data = discriminator</span></span>
|
|
1523
|
-
<span id="cb63-7"><a href="#cb63-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1524
|
-
<span id="cb63-8"><a href="#cb63-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>actual_tag <span class="op">!=</span> expected_tag<span class="op">)</span> <span class="op">{</span></span>
|
|
1525
|
-
<span id="cb63-9"><a href="#cb63-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> UNDEFINED_PTR<span class="op">;</span> <span class="co">// Pattern match failure</span></span>
|
|
1526
|
-
<span id="cb63-10"><a href="#cb63-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1527
|
-
<span id="cb63-11"><a href="#cb63-11" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1528
|
-
<span id="cb63-12"><a href="#cb63-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// Skip past header + discriminator</span></span>
|
|
1529
|
-
<span id="cb63-13"><a href="#cb63-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> child_ptr <span class="op">=</span> byte_ptr <span class="op">+</span> <span class="kw">sizeof</span><span class="op">(</span><span class="kw">struct</span> OptimalEncoding<span class="op">)</span> <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
|
|
1530
|
-
<span id="cb63-14"><a href="#cb63-14" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1531
|
-
<span id="cb63-15"><a href="#cb63-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_ptr_from_bytes<span class="op">(</span>child_ptr<span class="op">);</span></span>
|
|
1532
|
-
<span id="cb63-16"><a href="#cb63-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1533
|
-
<h4 id="product-operation"><strong>Product operation</strong></h4>
|
|
1534
|
-
<p>For product construction <code>{ field1, field2, ... }</code>:</p>
|
|
1535
|
-
<div class="sourceCode" id="cb64"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr construct_product<span class="op">(</span>DecoratedPtr<span class="op">*</span> field_ptrs<span class="op">,</span> <span class="dt">int</span> arity<span class="op">)</span> <span class="op">{</span></span>
|
|
1536
|
-
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// This is the primary point where memory allocation is required.</span></span>
|
|
1537
|
-
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a> ProductNode<span class="op">*</span> result <span class="op">=</span> allocate_product_node<span class="op">(</span>arity<span class="op">);</span></span>
|
|
1538
|
-
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1539
|
-
<span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Evaluate each field (possibly in parallel)</span></span>
|
|
1540
|
-
<span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> arity<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1541
|
-
<span id="cb64-7"><a href="#cb64-7" aria-hidden="true" tabindex="-1"></a> result<span class="op">-></span>fields<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> evaluate_expression<span class="op">(</span>field_ptrs<span class="op">[</span>i<span class="op">]);</span></span>
|
|
1542
|
-
<span id="cb64-8"><a href="#cb64-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1543
|
-
<span id="cb64-9"><a href="#cb64-9" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1544
|
-
<span id="cb64-10"><a href="#cb64-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_materialized_ptr<span class="op">(</span>result<span class="op">);</span></span>
|
|
1545
|
-
<span id="cb64-11"><a href="#cb64-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1546
|
-
<h4 id="built-in-call-operation"><strong>Built-in call
|
|
1547
|
-
operation</strong></h4>
|
|
1548
|
-
<p>For external functions <code>string_length</code>,
|
|
1549
|
-
<code>add_int</code>, etc.:</p>
|
|
1550
|
-
<div class="sourceCode" id="cb65"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr builtin_call<span class="op">(</span>DecoratedPtr input<span class="op">,</span> BuiltinFunc func<span class="op">)</span> <span class="op">{</span></span>
|
|
1551
|
-
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Force materialization of the input</span></span>
|
|
1552
|
-
<span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a> ExternalValue<span class="op">*</span> materialized <span class="op">=</span> force_external<span class="op">(</span>input<span class="op">);</span></span>
|
|
1553
|
-
<span id="cb65-4"><a href="#cb65-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1554
|
-
<span id="cb65-5"><a href="#cb65-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Delegate to external implementation</span></span>
|
|
1555
|
-
<span id="cb65-6"><a href="#cb65-6" aria-hidden="true" tabindex="-1"></a> ExternalValue<span class="op">*</span> result <span class="op">=</span> func<span class="op">-></span>call<span class="op">(</span>materialized<span class="op">);</span></span>
|
|
1556
|
-
<span id="cb65-7"><a href="#cb65-7" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1557
|
-
<span id="cb65-8"><a href="#cb65-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_external_ptr<span class="op">(</span>result<span class="op">);</span></span>
|
|
1558
|
-
<span id="cb65-9"><a href="#cb65-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1559
|
-
<h3 id="execution-strategy"><strong>6.10.3 Execution
|
|
1560
|
-
strategy</strong></h3>
|
|
1561
|
-
<ol type="1">
|
|
1562
|
-
<li><strong>Input setup</strong>: Place serialized input in heap, create
|
|
1563
|
-
root decorated pointer</li>
|
|
1564
|
-
<li><strong>Lazy evaluation</strong>: Transform decorated pointers
|
|
1565
|
-
without allocation when possible</li>
|
|
1566
|
-
<li><strong>Forced materialization</strong>: Allocate memory only when
|
|
1567
|
-
constructing products or calling built-ins</li>
|
|
1568
|
-
<li><strong>Reference counting</strong>: Share decorated pointers for
|
|
1569
|
-
common subexpressions</li>
|
|
1570
|
-
<li><strong>Output serialization</strong>: Convert final decorated
|
|
1571
|
-
pointer back to canonical bits</li>
|
|
1572
|
-
</ol>
|
|
1573
|
-
<h3 id="example-execution-trace"><strong>6.10.4 Example execution
|
|
1574
|
-
trace</strong></h3>
|
|
1575
|
-
<p>For program <code>\x.(x.data.head.value, x.name)</code> on input
|
|
1576
|
-
<code>{ name: "alice", data: [42, 17] }</code>:</p>
|
|
1577
|
-
<pre class="text"><code>Step 1: input_ptr = {bits: heap_start, offset: 0, state: C0_record}
|
|
1578
|
-
|
|
1579
|
-
Step 2: data_ptr = project_field(input_ptr, 1) // .data
|
|
1580
|
-
= {bits: heap_start, offset: 120, state: C0_list}
|
|
1581
|
-
|
|
1582
|
-
Step 3: head_ptr = match_union(data_ptr, CONS_TAG) // pattern match
|
|
1583
|
-
= {bits: heap_start, offset: 122, state: C0_cons}
|
|
1584
|
-
|
|
1585
|
-
Step 4: value_ptr = project_field(head_ptr, 0) // .value
|
|
1586
|
-
= {bits: heap_start, offset: 122, state: C0_int}
|
|
1587
|
-
|
|
1588
|
-
Step 5: name_ptr = project_field(input_ptr, 0) // .name
|
|
1589
|
-
= {bits: heap_start, offset: 8, state: C0_string}
|
|
1590
|
-
|
|
1591
|
-
Step 6: result_ptr = construct_product([value_ptr, name_ptr])
|
|
1592
|
-
// Note: memory allocation for the result tuple occurs here.</code></pre>
|
|
1593
|
-
<h3 id="optimization-opportunities-1"><strong>6.10.5 Optimization
|
|
1594
|
-
opportunities</strong></h3>
|
|
1595
|
-
<ul>
|
|
1596
|
-
<li><strong>Parallel field evaluation</strong> — Independent fields can
|
|
1597
|
-
be computed concurrently</li>
|
|
1598
|
-
<li><strong>Memoization</strong> — Cache decorated pointers for repeated
|
|
1599
|
-
subexpressions<br />
|
|
1600
|
-
</li>
|
|
1601
|
-
<li><strong>Streaming</strong> — Process parts of large inputs without
|
|
1602
|
-
loading everything</li>
|
|
1603
|
-
<li><strong>Zero-copy identity</strong> — <code>()</code> just returns
|
|
1604
|
-
the input decorated pointer</li>
|
|
1605
|
-
<li><strong>Prefix-free parsing</strong> — No backtracking needed,
|
|
1606
|
-
linear-time navigation</li>
|
|
1607
|
-
</ul>
|
|
1608
|
-
<p>This model provides <strong>optimal performance</strong> for sparse
|
|
1609
|
-
data access while maintaining the mathematical precision of k’s type
|
|
1610
|
-
system.</p>
|
|
1611
|
-
<hr />
|
|
1612
|
-
<h2 id="implementation-considerations"><strong>6.11 Implementation
|
|
1613
|
-
considerations</strong></h2>
|
|
1614
|
-
<h3 id="prefix-free-code-requirements"><strong>6.11.1 Prefix-free code
|
|
1615
|
-
requirements</strong></h3>
|
|
1616
|
-
<p>The execution model depends critically on <strong>prefix-free
|
|
1617
|
-
codes</strong> in the serialization:</p>
|
|
1618
|
-
<ul>
|
|
1619
|
-
<li><strong>Union discriminators</strong> — Fixed-length codes ensure
|
|
1620
|
-
constant-time tag reading</li>
|
|
1621
|
-
<li><strong>External data</strong> — Length-prefixed to enable skipping
|
|
1622
|
-
without parsing</li>
|
|
1623
|
-
<li><strong>Product fields</strong> — Implicit boundaries defined by
|
|
1624
|
-
type structure</li>
|
|
1625
|
-
</ul>
|
|
1626
|
-
<p>This enables the <code>skip_field()</code> function to advance
|
|
1627
|
-
pointers without full deserialization.</p>
|
|
1628
|
-
<h3 id="reference-counting-and-caching"><strong>6.11.2 Reference
|
|
1629
|
-
counting and caching</strong></h3>
|
|
1630
|
-
<p>Decorated pointers should be reference-counted for several
|
|
1631
|
-
reasons:</p>
|
|
1632
|
-
<p>Benefits:</p>
|
|
1633
|
-
<ul>
|
|
1634
|
-
<li><strong>Sharing</strong> — Multiple references to the same
|
|
1635
|
-
subexpression</li>
|
|
1636
|
-
<li><strong>Caching</strong> — Avoid recomputation of expensive
|
|
1637
|
-
operations</li>
|
|
1638
|
-
<li><strong>Memory efficiency</strong> — Single copy of large serialized
|
|
1639
|
-
inputs</li>
|
|
1640
|
-
</ul>
|
|
1641
|
-
<h3 id="parallel-evaluation"><strong>6.11.3 Parallel
|
|
1642
|
-
evaluation</strong></h3>
|
|
1643
|
-
<p>Product construction offers natural parallelization:</p>
|
|
1644
|
-
<div class="sourceCode" id="cb67"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a>DecoratedPtr construct_product_parallel<span class="op">(</span>DecoratedPtr<span class="op">*</span> field_ptrs<span class="op">,</span> <span class="dt">int</span> arity<span class="op">)</span> <span class="op">{</span></span>
|
|
1645
|
-
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a> ProductNode<span class="op">*</span> result <span class="op">=</span> allocate_product_node<span class="op">(</span>arity<span class="op">);</span></span>
|
|
1646
|
-
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1647
|
-
<span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a> <span class="pp">#pragma omp parallel for</span></span>
|
|
1648
|
-
<span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> arity<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
|
1649
|
-
<span id="cb67-6"><a href="#cb67-6" aria-hidden="true" tabindex="-1"></a> result<span class="op">-></span>fields<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> evaluate_expression<span class="op">(</span>field_ptrs<span class="op">[</span>i<span class="op">]);</span></span>
|
|
1650
|
-
<span id="cb67-7"><a href="#cb67-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1651
|
-
<span id="cb67-8"><a href="#cb67-8" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1652
|
-
<span id="cb67-9"><a href="#cb67-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> make_materialized_ptr<span class="op">(</span>result<span class="op">);</span></span>
|
|
1653
|
-
<span id="cb67-10"><a href="#cb67-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1654
|
-
<p>Each field evaluation is independent and can run on separate
|
|
1655
|
-
threads.</p>
|
|
1656
|
-
<h3 id="memory-layout-optimization"><strong>6.11.4 Memory layout
|
|
1657
|
-
optimization</strong></h3>
|
|
1658
|
-
<p>The input heap should be designed for efficient navigation:</p>
|
|
1659
|
-
<div class="sourceCode" id="cb68"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> InputHeap <span class="op">{</span></span>
|
|
1660
|
-
<span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">uint8_t</span><span class="op">*</span> serialized_data<span class="op">;</span> <span class="co">// the original bitstream</span></span>
|
|
1661
|
-
<span id="cb68-3"><a href="#cb68-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span> total_bits<span class="op">;</span> <span class="co">// total size</span></span>
|
|
1662
|
-
<span id="cb68-4"><a href="#cb68-4" aria-hidden="true" tabindex="-1"></a> </span>
|
|
1663
|
-
<span id="cb68-5"><a href="#cb68-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Optional: precomputed navigation table for large inputs</span></span>
|
|
1664
|
-
<span id="cb68-6"><a href="#cb68-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> <span class="op">{</span></span>
|
|
1665
|
-
<span id="cb68-7"><a href="#cb68-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">size_t</span><span class="op">*</span> field_offsets<span class="op">;</span> <span class="co">// byte offsets for major fields</span></span>
|
|
1666
|
-
<span id="cb68-8"><a href="#cb68-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> table_size<span class="op">;</span> <span class="co">// number of cached offsets</span></span>
|
|
1667
|
-
<span id="cb68-9"><a href="#cb68-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> navigation_cache<span class="op">;</span></span>
|
|
1668
|
-
<span id="cb68-10"><a href="#cb68-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1669
|
-
<p>For very large inputs, precomputing field offsets can eliminate
|
|
1670
|
-
repeated prefix-free parsing.</p>
|
|
1671
|
-
<hr />
|
|
1672
|
-
<h2 id="final-summary"><strong>6.12 Final summary</strong></h2>
|
|
1673
|
-
<p>This unified design achieves several important goals:</p>
|
|
1674
|
-
<ol type="1">
|
|
1675
|
-
<li><strong>Zero-copy operations</strong> — Identity and projection work
|
|
1676
|
-
directly on serialized data</li>
|
|
1677
|
-
<li><strong>Demand-driven materialization</strong> — Memory allocation
|
|
1678
|
-
only when necessary</li>
|
|
1679
|
-
<li><strong>External type integration</strong> — Built-ins fit
|
|
1680
|
-
seamlessly into the execution model</li>
|
|
1681
|
-
<li><strong>Parallel execution</strong> — Natural parallelization
|
|
1682
|
-
opportunities</li>
|
|
1683
|
-
<li><strong>Streaming capability</strong> — Process large inputs with
|
|
1684
|
-
bounded memory</li>
|
|
1685
|
-
</ol>
|
|
1686
|
-
<p>The decorated pointer model provides a clean abstraction that bridges
|
|
1687
|
-
the gap between the mathematical elegance of k’s type system and the
|
|
1688
|
-
performance requirements of real-world data processing.</p>
|
|
1689
|
-
<p><strong>Key insight</strong>: By treating serialized data as the
|
|
1690
|
-
primary representation and materialized structures as secondary
|
|
1691
|
-
optimization, we invert the traditional approach and achieve much better
|
|
1692
|
-
performance for sparse data access patterns.</p>
|
|
1693
|
-
<h3 id="hardware-optimized-encoding-summary"><strong>6.12.1
|
|
1694
|
-
Hardware-optimized encoding summary</strong></h3>
|
|
1695
|
-
<p>The final encoding strategy balances theoretical optimality with
|
|
1696
|
-
practical hardware constraints:</p>
|
|
1697
|
-
<p><strong>Trade-offs achieved</strong>:</p>
|
|
1698
|
-
<ul>
|
|
1699
|
-
<li><strong>Space efficiency</strong>: 80-90% of theoretical
|
|
1700
|
-
optimum</li>
|
|
1701
|
-
<li><strong>Decode performance</strong>: 5-10× faster than bit-level
|
|
1702
|
-
encoding<br />
|
|
1703
|
-
</li>
|
|
1704
|
-
<li><strong>Cache behavior</strong>: Excellent (word-aligned, sequential
|
|
1705
|
-
access)</li>
|
|
1706
|
-
<li><strong>SIMD compatibility</strong>: Yes (bulk discriminator
|
|
1707
|
-
processing)</li>
|
|
1708
|
-
<li><strong>Architecture agnostic</strong>: Optimized for x86-64 and
|
|
1709
|
-
ARM64</li>
|
|
1710
|
-
</ul>
|
|
1711
|
-
<p><strong>Performance characteristics</strong>:</p>
|
|
1712
|
-
<pre class="text"><code>Operation Hardware-optimized Bit-level optimal
|
|
1713
|
-
Field access 2-8 cycles 50-100 cycles
|
|
1714
|
-
Union matching 1-3 cycles 20-40 cycles
|
|
1715
|
-
Memory bandwidth 95% theoretical 60% theoretical
|
|
1716
|
-
Cache miss ratio <5% >25%</code></pre>
|
|
1717
|
-
<p><strong>Recommended for</strong>:</p>
|
|
1718
|
-
<ul>
|
|
1719
|
-
<li><strong>Production systems</strong> requiring high performance</li>
|
|
1720
|
-
<li><strong>Streaming applications</strong> with large data volumes</li>
|
|
1721
|
-
<li><strong>Mobile/embedded</strong> systems with limited CPU
|
|
1722
|
-
resources</li>
|
|
1723
|
-
<li><strong>SIMD-heavy workloads</strong> processing bulk data</li>
|
|
1724
|
-
</ul>
|
|
1725
|
-
<p>The hardware-optimized approach provides the best practical balance
|
|
1726
|
-
for real-world k implementations.</p>
|
|
1727
|
-
<hr />
|
|
1728
|
-
<hr />
|
|
1729
|
-
<h1 id="chapter-7-the-partial-function-abi">Chapter 7 — The Partial
|
|
1730
|
-
Function ABI</h1>
|
|
1731
|
-
<h2 id="purpose"><strong>7.1 Purpose</strong></h2>
|
|
1732
|
-
<p>The <strong>application binary interface (ABI)</strong> defines how
|
|
1733
|
-
partial functions in <code>k</code> are represented and invoked at
|
|
1734
|
-
runtime. Its goal is to make all functions - whether user-defined or
|
|
1735
|
-
compiled - compatible with the same calling convention and data
|
|
1736
|
-
layout.</p>
|
|
1737
|
-
<p>Every compiled <code>k</code> function receives a single argument (a
|
|
1738
|
-
value tree) and may either produce a result or remain undefined. The ABI
|
|
1739
|
-
provides a uniform way to express both outcomes.</p>
|
|
1740
|
-
<hr />
|
|
1741
|
-
<h2 id="function-result-representation"><strong>7.2 Function result
|
|
1742
|
-
representation</strong></h2>
|
|
1743
|
-
<p>The result of every function call is a pair of fields:</p>
|
|
1744
|
-
<div class="sourceCode" id="cb70"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt <span class="op">{</span></span>
|
|
1745
|
-
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">bool</span> ok<span class="op">;</span> <span class="co">// 1 if function is defined for the given input</span></span>
|
|
1746
|
-
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">struct</span> KNode<span class="op">*</span> val<span class="op">;</span> <span class="co">// valid only if ok == true</span></span>
|
|
1747
|
-
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
|
1748
|
-
<p>If <code>ok == 1</code>, the function succeeded and <code>val</code>
|
|
1749
|
-
points to the root node of the resulting value. If <code>ok == 0</code>,
|
|
1750
|
-
the function is undefined for the input, and <code>val</code> is
|
|
1751
|
-
meaningless.</p>
|
|
1752
|
-
<p>This structure carries both the success flag and the value pointer,
|
|
1753
|
-
allowing partiality to be expressed directly in generated code.</p>
|
|
1754
|
-
<hr />
|
|
1755
|
-
<h2 id="function-parameter-representation"><strong>7.3 Function
|
|
1756
|
-
parameter representation</strong></h2>
|
|
1757
|
-
<p>Each function takes exactly one parameter:</p>
|
|
1758
|
-
<div class="sourceCode" id="cb71"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">;</span></span></code></pre></div>
|
|
1759
|
-
<p>The parameter points to the root of the input value. Since all values
|
|
1760
|
-
are immutable, the function must not modify this structure.</p>
|
|
1761
|
-
<hr />
|
|
1762
|
-
<h2 id="calling-convention"><strong>7.4 Calling convention</strong></h2>
|
|
1763
|
-
<p>Every <code>k</code> function compiled to machine code follows this
|
|
1764
|
-
C-style signature:</p>
|
|
1765
|
-
<div class="sourceCode" id="cb72"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt k_function<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">);</span></span></code></pre></div>
|
|
1766
|
-
<p>The return value indicates success or failure. The convention is
|
|
1767
|
-
uniform for all functions, regardless of the specific types
|
|
1768
|
-
involved.</p>
|
|
1769
|
-
<hr />
|
|
1770
|
-
<h2 id="core-runtime-operations"><strong>7.5 Core runtime
|
|
1771
|
-
operations</strong></h2>
|
|
1772
|
-
<p>The runtime provides a small set of primitive functions implementing
|
|
1773
|
-
the fundamental operations of <code>k</code>:</p>
|
|
1774
|
-
<table>
|
|
1775
|
-
<colgroup>
|
|
1776
|
-
<col style="width: 32%" />
|
|
1777
|
-
<col style="width: 25%" />
|
|
1778
|
-
<col style="width: 42%" />
|
|
1779
|
-
</colgroup>
|
|
1780
|
-
<thead>
|
|
1781
|
-
<tr>
|
|
1782
|
-
<th>Operation</th>
|
|
1783
|
-
<th>Purpose</th>
|
|
1784
|
-
<th>Result</th>
|
|
1785
|
-
</tr>
|
|
1786
|
-
</thead>
|
|
1787
|
-
<tbody>
|
|
1788
|
-
<tr>
|
|
1789
|
-
<td><code>k_project(input, label_id)</code></td>
|
|
1790
|
-
<td>projection <code>.label</code></td>
|
|
1791
|
-
<td>defined if the field or variant <code>label_id</code> exists</td>
|
|
1792
|
-
</tr>
|
|
1793
|
-
<tr>
|
|
1794
|
-
<td><code>k_make_product(state, children[], n)</code></td>
|
|
1795
|
-
<td>construct a product node</td>
|
|
1796
|
-
<td>always defined</td>
|
|
1797
|
-
</tr>
|
|
1798
|
-
<tr>
|
|
1799
|
-
<td><code>k_make_union(state, tag, child)</code></td>
|
|
1800
|
-
<td>construct a union node</td>
|
|
1801
|
-
<td>always defined</td>
|
|
1802
|
-
</tr>
|
|
1803
|
-
<tr>
|
|
1804
|
-
<td><code>k_fail()</code></td>
|
|
1805
|
-
<td>represent undefined result</td>
|
|
1806
|
-
<td>returns <code>{ ok = 0 }</code></td>
|
|
1807
|
-
</tr>
|
|
1808
|
-
<tr>
|
|
1809
|
-
<td><code>k_unit()</code></td>
|
|
1810
|
-
<td>return the constant unit node</td>
|
|
1811
|
-
<td>returns <code>{ ok = 1, val = &unit_node }</code></td>
|
|
1812
|
-
</tr>
|
|
1813
|
-
</tbody>
|
|
1814
|
-
</table>
|
|
1815
|
-
<p>All user-defined functions can be compiled entirely in terms of these
|
|
1816
|
-
operations.</p>
|
|
1817
|
-
<hr />
|
|
1818
|
-
<h2 id="metadata-tables"><strong>7.6 Metadata tables</strong></h2>
|
|
1819
|
-
<p>To interpret or construct nodes correctly, the runtime holds constant
|
|
1820
|
-
tables derived from canonical type definitions:</p>
|
|
1821
|
-
<ul>
|
|
1822
|
-
<li><code>state_kind[state]</code> — <code>0</code> for product,
|
|
1823
|
-
<code>1</code> for union,</li>
|
|
1824
|
-
<li><code>state_arity[state]</code> — number of child fields for
|
|
1825
|
-
products (always 1 for unions),</li>
|
|
1826
|
-
<li><code>field_index[state][label_id]</code> — index of field in
|
|
1827
|
-
product (or <code>-1</code> if absent),</li>
|
|
1828
|
-
<li><code>variant_index[state][label_id]</code> — index of variant in
|
|
1829
|
-
union (or <code>-1</code> if absent).</li>
|
|
1830
|
-
</ul>
|
|
1831
|
-
<p>These tables are read-only and known at compile time for each
|
|
1832
|
-
canonical type.</p>
|
|
1833
|
-
<hr />
|
|
1834
|
-
<h2 id="example-projection"><strong>7.7 Example:
|
|
1835
|
-
projection</strong></h2>
|
|
1836
|
-
<p>To implement the projection <code>.x</code>:</p>
|
|
1837
|
-
<div class="sourceCode" id="cb73"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt k_project_x<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">)</span> <span class="op">{</span></span>
|
|
1838
|
-
<span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> state <span class="op">=</span> input<span class="op">-></span>state<span class="op">;</span></span>
|
|
1839
|
-
<span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> kind <span class="op">=</span> state_kind<span class="op">[</span>state<span class="op">];</span></span>
|
|
1840
|
-
<span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
1841
|
-
<span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>kind <span class="op">==</span> PRODUCT<span class="op">)</span> <span class="op">{</span></span>
|
|
1842
|
-
<span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> idx <span class="op">=</span> field_index<span class="op">[</span>state<span class="op">][</span><span class="st">"x"</span><span class="op">];</span></span>
|
|
1843
|
-
<span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>idx <span class="op"><</span> <span class="dv">0</span> <span class="op">||</span> idx <span class="op">>=</span> input<span class="op">-></span>arity<span class="op">)</span></span>
|
|
1844
|
-
<span id="cb73-8"><a href="#cb73-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
|
1845
|
-
<span id="cb73-9"><a href="#cb73-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">1</span><span class="op">,</span> input<span class="op">-></span>child<span class="op">[</span>idx<span class="op">]};</span></span>
|
|
1846
|
-
<span id="cb73-10"><a href="#cb73-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1847
|
-
<span id="cb73-11"><a href="#cb73-11" aria-hidden="true" tabindex="-1"></a></span>
|
|
1848
|
-
<span id="cb73-12"><a href="#cb73-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>kind <span class="op">==</span> UNION<span class="op">)</span> <span class="op">{</span></span>
|
|
1849
|
-
<span id="cb73-13"><a href="#cb73-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> tag <span class="op">=</span> variant_index<span class="op">[</span>state<span class="op">][</span><span class="st">"x"</span><span class="op">];</span></span>
|
|
1850
|
-
<span id="cb73-14"><a href="#cb73-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tag <span class="op"><</span> <span class="dv">0</span> <span class="op">||</span> input<span class="op">-></span>tag <span class="op">!=</span> tag<span class="op">)</span></span>
|
|
1851
|
-
<span id="cb73-15"><a href="#cb73-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
|
1852
|
-
<span id="cb73-16"><a href="#cb73-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">1</span><span class="op">,</span> input<span class="op">-></span>child<span class="op">[</span><span class="dv">0</span><span class="op">]};</span></span>
|
|
1853
|
-
<span id="cb73-17"><a href="#cb73-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
|
1854
|
-
<span id="cb73-18"><a href="#cb73-18" aria-hidden="true" tabindex="-1"></a></span>
|
|
1855
|
-
<span id="cb73-19"><a href="#cb73-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">(</span><span class="kw">struct</span> KOpt<span class="op">){</span><span class="dv">0</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
|
1856
|
-
<span id="cb73-20"><a href="#cb73-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
|
1857
|
-
<p>This code demonstrates the generic principle: the projection is
|
|
1858
|
-
defined if and only if the input has a field or variant named
|
|
1859
|
-
<code>x</code>.</p>
|
|
1860
|
-
<hr />
|
|
1861
|
-
<h2 id="error-propagation"><strong>7.8 Error propagation</strong></h2>
|
|
1862
|
-
<p>When one function calls another, the success flag <code>ok</code>
|
|
1863
|
-
propagates forward. If a subcall returns <code>ok == 0</code>, the
|
|
1864
|
-
caller must return <code>{0, NULL}</code> immediately. This makes
|
|
1865
|
-
undefinedness explicit and local—no exceptions, no global flags.</p>
|
|
1866
|
-
<hr />
|
|
1867
|
-
<h2 id="summary-5"><strong>7.9 Summary</strong></h2>
|
|
1868
|
-
<ul>
|
|
1869
|
-
<li>Every function has the form <code>KOpt f(KNode*)</code>.</li>
|
|
1870
|
-
<li>Partiality is expressed by the <code>ok</code> flag.</li>
|
|
1871
|
-
<li>Runtime operations handle projection and construction.</li>
|
|
1872
|
-
<li>Metadata tables describe field positions and variant indices.</li>
|
|
1873
|
-
<li>By inspecting <code>arity</code>, <code>state</code>, and
|
|
1874
|
-
<code>tag</code>, the runtime can interpret any value correctly.</li>
|
|
1875
|
-
<li>This ABI ensures all generated and runtime functions can
|
|
1876
|
-
interoperate safely.</li>
|
|
1877
|
-
</ul>
|
|
1878
|
-
<hr />
|
|
1879
|
-
<hr />
|
|
1880
|
-
<h1 id="chapter-8-operational-semantics-and-execution">Chapter 8 —
|
|
1881
|
-
Operational Semantics and Execution</h1>
|
|
1882
|
-
<h2 id="purpose-1"><strong>8.1 Purpose</strong></h2>
|
|
1883
|
-
<p>The <strong>operational semantics</strong> of <code>k</code> describe
|
|
1884
|
-
how expressions are evaluated step by step on actual value trees. It
|
|
1885
|
-
defines when a function is <em>defined</em> for a particular input and
|
|
1886
|
-
what value it returns. All execution—interpretive or compiled—follows
|
|
1887
|
-
these rules.</p>
|
|
1888
|
-
<hr />
|
|
1889
|
-
<h2 id="evaluation-relation"><strong>8.2 Evaluation
|
|
1890
|
-
relation</strong></h2>
|
|
1891
|
-
<p>Evaluation is written as:</p>
|
|
1892
|
-
<pre class="text"><code>⟨ e , v ⟩ ⇓ r</code></pre>
|
|
1893
|
-
<p>meaning that expression <code>e</code> applied to value
|
|
1894
|
-
<code>v</code> yields result <code>r</code>. If <code>e</code> is
|
|
1895
|
-
undefined for <code>v</code>, the relation does not hold.</p>
|
|
1896
|
-
<p><code>r</code> is always a tree (or node) in memory, represented as
|
|
1897
|
-
described in Chapter 6. Undefined results are expressed by the absence
|
|
1898
|
-
of any rule that produces <code>r</code>.</p>
|
|
1899
|
-
<hr />
|
|
1900
|
-
<h2 id="rules-for-base-expressions"><strong>8.3 Rules for base
|
|
1901
|
-
expressions</strong></h2>
|
|
1902
|
-
<h3 id="identity"><strong>Identity</strong></h3>
|
|
1903
|
-
<pre class="text"><code>⟨ () , v ⟩ ⇓ v</code></pre>
|
|
1904
|
-
<p>The empty composition <code>()</code> returns its argument
|
|
1905
|
-
unchanged.</p>
|
|
1906
|
-
<h3 id="projection"><strong>Projection</strong></h3>
|
|
1907
|
-
<p>Let <code>label</code> be a field or variant name. If <code>v</code>
|
|
1908
|
-
has a child under <code>label</code>,</p>
|
|
1909
|
-
<pre class="text"><code>⟨ .label , v ⟩ ⇓ v.label</code></pre>
|
|
1910
|
-
<p>Otherwise the projection is undefined.</p>
|
|
1911
|
-
<h3 id="type-expression"><strong>Type expression</strong></h3>
|
|
1912
|
-
<p>For a type <code>T</code>,</p>
|
|
1913
|
-
<pre class="text"><code>⟨ $T , v ⟩ ⇓ v if v ∈ T</code></pre>
|
|
1914
|
-
<p>and undefined otherwise. Type expressions thus act as identity
|
|
1915
|
-
functions restricted to their type.</p>
|
|
1916
|
-
<hr />
|
|
1917
|
-
<h2 id="rules-for-composition"><strong>8.4 Rules for
|
|
1918
|
-
composition</strong></h2>
|
|
1919
|
-
<h3 id="sequential-composition"><strong>Sequential
|
|
1920
|
-
composition</strong></h3>
|
|
1921
|
-
<pre class="text"><code>⟨ (f g) , v ⟩ ⇓ r</code></pre>
|
|
1922
|
-
<p>if there exists <code>u</code> such that <code>⟨ f , v ⟩ ⇓ u</code>
|
|
1923
|
-
and <code>⟨ g , u ⟩ ⇓ r</code>.</p>
|
|
1924
|
-
<p>If either step is undefined, the composition is undefined. Because
|
|
1925
|
-
composition is associative,</p>
|
|
1926
|
-
<pre class="text"><code>(f (g h)) ≡ ((f g) h) ≡ (f g h)</code></pre>
|
|
1927
|
-
<p>Parentheses are needed only for <code>()</code>.</p>
|
|
1928
|
-
<hr />
|
|
1929
|
-
<h2 id="rules-for-product-composition"><strong>8.5 Rules for product
|
|
1930
|
-
composition</strong></h2>
|
|
1931
|
-
<pre class="text"><code>⟨ { f₁ l₁ , f₂ l₂ , … , fₙ lₙ } , v ⟩ ⇓ { r₁ l₁ , r₂ l₂ , … , rₙ lₙ }</code></pre>
|
|
1932
|
-
<p>if and only if all subfunctions <code>fᵢ</code> are defined on
|
|
1933
|
-
<code>v</code> and yield <code>rᵢ</code>. If any subfunction is
|
|
1934
|
-
undefined, the whole product composition is undefined.</p>
|
|
1935
|
-
<p>A product composition constructs a new product node; each result
|
|
1936
|
-
<code>rᵢ</code> becomes one child in canonical field order.</p>
|
|
1937
|
-
<hr />
|
|
1938
|
-
<h2 id="rules-for-union-composition"><strong>8.6 Rules for union
|
|
1939
|
-
composition</strong></h2>
|
|
1940
|
-
<pre class="text"><code>⟨ < f₁ , f₂ , … , fₙ > , v ⟩ ⇓ rⱼ</code></pre>
|
|
1941
|
-
<p>if there exists the smallest index <code>j</code> such that
|
|
1942
|
-
<code>⟨ fⱼ , v ⟩ ⇓ rⱼ</code>.</p>
|
|
1943
|
-
<p>If no subfunction is defined, the union composition is undefined.</p>
|
|
1944
|
-
<hr />
|
|
1945
|
-
<h2 id="rules-for-filters"><strong>8.7 Rules for filters</strong></h2>
|
|
1946
|
-
<p>If a filter <code>F</code> matches a single type <code>T</code></p>
|
|
1947
|
-
<pre class="text"><code>⟨ ?F , v ⟩ ⇓ ⟨ $T , v ⟩ </code></pre>
|
|
1948
|
-
<p>otherwise it is an identity</p>
|
|
1949
|
-
<pre class="text"><code>⟨ ?F , v ⟩ ⇓ v</code></pre>
|
|
1950
|
-
<p>Filters therefore act as compile time annotations for type checking
|
|
1951
|
-
only. They are ignored at run-time, unless they lead to fully typed
|
|
1952
|
-
expressions (i.e., can be replaced by a type).</p>
|
|
1953
|
-
<hr />
|
|
1954
|
-
<h2 id="evaluation-order"><strong>8.8 Evaluation order</strong></h2>
|
|
1955
|
-
<p>Evaluation proceeds left to right. In products, all subfunctions
|
|
1956
|
-
receive the same input; in unions, later functions are evaluated only if
|
|
1957
|
-
earlier ones fail.</p>
|
|
1958
|
-
<p>The semantics are deterministic: for any given input, at most one
|
|
1959
|
-
result tree can be produced.</p>
|
|
1960
|
-
<hr />
|
|
1961
|
-
<h2 id="example-1"><strong>8.9 Example</strong></h2>
|
|
1962
|
-
<p>Given:</p>
|
|
1963
|
-
<pre class="k-lang"><code>$bool = < {} true, {} false >;
|
|
1964
|
-
neg = $bool < .true {{ } false}, .false {{ } true} > $bool;</code></pre>
|
|
1965
|
-
<p>and input value <code>{ {} true }</code> of type <code>bool</code>,
|
|
1966
|
-
evaluation steps are:</p>
|
|
1967
|
-
<ol type="1">
|
|
1968
|
-
<li><code>⟨ $bool , { {} true } ⟩ ⇓ { {} true }</code></li>
|
|
1969
|
-
<li><code>⟨ < .true {{ } false}, .false {{ } true} > , { {} true } ⟩ ⇓ {{ } false}</code></li>
|
|
1970
|
-
<li><code>⟨ $bool , {{ } false} ⟩ ⇓ {{ } false}</code></li>
|
|
1971
|
-
</ol>
|
|
1972
|
-
<p>Final result: <code>{{ } false}</code>. If the input were of another
|
|
1973
|
-
type, step 1 would be undefined.</p>
|
|
1974
|
-
<hr />
|
|
1975
|
-
<h2 id="implementation-correspondence"><strong>8.10 Implementation
|
|
1976
|
-
correspondence</strong></h2>
|
|
1977
|
-
<p>The evaluation rules map directly onto the runtime ABI:</p>
|
|
1978
|
-
<table>
|
|
1979
|
-
<thead>
|
|
1980
|
-
<tr>
|
|
1981
|
-
<th>Semantic rule</th>
|
|
1982
|
-
<th>Runtime operation</th>
|
|
1983
|
-
</tr>
|
|
1984
|
-
</thead>
|
|
1985
|
-
<tbody>
|
|
1986
|
-
<tr>
|
|
1987
|
-
<td>Projection</td>
|
|
1988
|
-
<td><code>k_project</code></td>
|
|
1989
|
-
</tr>
|
|
1990
|
-
<tr>
|
|
1991
|
-
<td>Product composition</td>
|
|
1992
|
-
<td>multiple subcalls + <code>k_make_product</code></td>
|
|
1993
|
-
</tr>
|
|
1994
|
-
<tr>
|
|
1995
|
-
<td>Union composition</td>
|
|
1996
|
-
<td>sequential subcalls with early return</td>
|
|
1997
|
-
</tr>
|
|
1998
|
-
<tr>
|
|
1999
|
-
<td>Type</td>
|
|
2000
|
-
<td>runtime check of <code>state</code></td>
|
|
2001
|
-
</tr>
|
|
2002
|
-
<tr>
|
|
2003
|
-
<td>Composition</td>
|
|
2004
|
-
<td>function call chain</td>
|
|
2005
|
-
</tr>
|
|
2006
|
-
</tbody>
|
|
2007
|
-
</table>
|
|
2008
|
-
<p>In compiled form, the <code>ok</code> flag of <code>KOpt</code>
|
|
2009
|
-
represents whether a rule applies; the node pointer represents the
|
|
2010
|
-
result value.</p>
|
|
2011
|
-
<hr />
|
|
2012
|
-
<h2 id="summary-6"><strong>8.11 Summary</strong></h2>
|
|
2013
|
-
<ul>
|
|
2014
|
-
<li>Execution follows deterministic, left-to-right rules.</li>
|
|
2015
|
-
<li>All expressions denote partial functions on value trees.</li>
|
|
2016
|
-
<li>Type expressions act as restricted identities.</li>
|
|
2017
|
-
<li>Composition is associative; undefined propagates automatically.</li>
|
|
2018
|
-
<li>Runtime semantics match the formal evaluation relation exactly.</li>
|
|
2019
|
-
</ul>
|
|
2020
|
-
<hr />
|
|
2021
|
-
<hr />
|
|
2022
|
-
<h1 id="chapter-9-compiler-architecture">Chapter 9 — Compiler
|
|
2023
|
-
Architecture</h1>
|
|
2024
|
-
<h2 id="what-the-compiler-does"><strong>9.1 What the compiler
|
|
2025
|
-
does</strong></h2>
|
|
2026
|
-
<p>A <em>compiler</em> for the <code>k</code> language is a program that
|
|
2027
|
-
reads another program (written in <code>k</code>) and produces a
|
|
2028
|
-
lower-level version of it. The lower-level version can then be executed
|
|
2029
|
-
efficiently by a computer.</p>
|
|
2030
|
-
<p>For <code>k</code>, the compiler’s task is simple in concept:</p>
|
|
2031
|
-
<ol type="1">
|
|
2032
|
-
<li><strong>Read</strong> the definitions of types and functions.</li>
|
|
2033
|
-
<li><strong>Understand</strong> their structure and the relationships
|
|
2034
|
-
between them.</li>
|
|
2035
|
-
<li><strong>Translate</strong> them into equivalent instructions that
|
|
2036
|
-
follow the runtime conventions described in Chapters 6–8.</li>
|
|
2037
|
-
</ol>
|
|
2038
|
-
<p>The compiler must ensure that every function in the source program
|
|
2039
|
-
becomes a machine-level function that behaves in exactly the same way:
|
|
2040
|
-
it takes a value as input, may or may not be defined for it, and, if
|
|
2041
|
-
defined, produces another value.</p>
|
|
2042
|
-
<hr />
|
|
2043
|
-
<h2 id="the-main-stages"><strong>9.2 The main stages</strong></h2>
|
|
2044
|
-
<p>A <code>k</code> compiler is organized as a sequence of well-defined
|
|
2045
|
-
stages. Each stage transforms one representation of the program into
|
|
2046
|
-
another, simpler one.</p>
|
|
2047
|
-
<ol type="1">
|
|
2048
|
-
<li><p><strong>Reading and parsing</strong> — The compiler converts the
|
|
2049
|
-
source text into a tree of syntactic objects. This tree is called the
|
|
2050
|
-
<em>abstract syntax tree</em> (AST). It records the structure of
|
|
2051
|
-
expressions such as <code>{ .x a, .y b }</code> or
|
|
2052
|
-
<code>< .x, .y ></code>.</p></li>
|
|
2053
|
-
<li><p><strong>Type analysis and normalization</strong> — The compiler
|
|
2054
|
-
expands type names, checks their correctness, and replaces all filters
|
|
2055
|
-
and meta-variables by concrete type information, following the procedure
|
|
2056
|
-
from Chapter 5. The result is a fully typed AST.</p></li>
|
|
2057
|
-
<li><p><strong>Preparation for execution</strong> — The compiler builds
|
|
2058
|
-
a <em>type table</em> for all canonical type states (C0, C1, …). For
|
|
2059
|
-
each type, it records whether it is a product or a union and the number
|
|
2060
|
-
and names of its fields or variants. These tables become the metadata
|
|
2061
|
-
used at runtime.</p></li>
|
|
2062
|
-
<li><p><strong>Code generation</strong> — Finally, the compiler walks
|
|
2063
|
-
through the typed AST and produces an equivalent description in a
|
|
2064
|
-
lower-level form that follows the runtime conventions: functions
|
|
2065
|
-
returning a success flag and a value pointer. This form can be expressed
|
|
2066
|
-
directly in C or in the <em>LLVM intermediate representation</em>, which
|
|
2067
|
-
is a platform-independent format understood by many compilers.</p></li>
|
|
2068
|
-
</ol>
|
|
2069
|
-
<hr />
|
|
2070
|
-
<h2 id="internal-structure"><strong>9.3 Internal structure</strong></h2>
|
|
2071
|
-
<p>A minimal compiler can be viewed as three connected modules:</p>
|
|
2072
|
-
<ul>
|
|
2073
|
-
<li><strong>Front end</strong> — reads source code, builds the AST,
|
|
2074
|
-
performs type analysis.</li>
|
|
2075
|
-
<li><strong>Middle</strong> — resolves all references, normalizes types,
|
|
2076
|
-
and simplifies expressions.</li>
|
|
2077
|
-
<li><strong>Back end</strong> — produces the executable form.</li>
|
|
2078
|
-
</ul>
|
|
2079
|
-
<p>Although these terms are traditional, the distinction is simple: the
|
|
2080
|
-
front end <em>understands</em> the program, the back end <em>emits</em>
|
|
2081
|
-
it, and the middle part connects the two.</p>
|
|
2082
|
-
<hr />
|
|
2083
|
-
<h2 id="data-kept-by-the-compiler"><strong>9.4 Data kept by the
|
|
2084
|
-
compiler</strong></h2>
|
|
2085
|
-
<p>During translation the compiler maintains several tables:</p>
|
|
2086
|
-
<table>
|
|
2087
|
-
<colgroup>
|
|
2088
|
-
<col style="width: 21%" />
|
|
2089
|
-
<col style="width: 78%" />
|
|
2090
|
-
</colgroup>
|
|
2091
|
-
<thead>
|
|
2092
|
-
<tr>
|
|
2093
|
-
<th>Name</th>
|
|
2094
|
-
<th>Purpose</th>
|
|
2095
|
-
</tr>
|
|
2096
|
-
</thead>
|
|
2097
|
-
<tbody>
|
|
2098
|
-
<tr>
|
|
2099
|
-
<td><strong>Type table</strong></td>
|
|
2100
|
-
<td>Maps type names to canonical forms and assigns numeric state
|
|
2101
|
-
IDs.</td>
|
|
2102
|
-
</tr>
|
|
2103
|
-
<tr>
|
|
2104
|
-
<td><strong>Field table</strong></td>
|
|
2105
|
-
<td>For each product type, records the order and index of its
|
|
2106
|
-
fields.</td>
|
|
2107
|
-
</tr>
|
|
2108
|
-
<tr>
|
|
2109
|
-
<td><strong>Variant table</strong></td>
|
|
2110
|
-
<td>For each union type, records the tags and their numeric
|
|
2111
|
-
indices.</td>
|
|
2112
|
-
</tr>
|
|
2113
|
-
<tr>
|
|
2114
|
-
<td><strong>Function table</strong></td>
|
|
2115
|
-
<td>Associates function names with their input and output types.</td>
|
|
2116
|
-
</tr>
|
|
2117
|
-
</tbody>
|
|
2118
|
-
</table>
|
|
2119
|
-
<p>These tables ensure that generated code can find fields and variants
|
|
2120
|
-
by number rather than by name, which simplifies execution.</p>
|
|
2121
|
-
<hr />
|
|
2122
|
-
<h2 id="example-of-transformation"><strong>9.5 Example of
|
|
2123
|
-
transformation</strong></h2>
|
|
2124
|
-
<p>Consider a simple k program:</p>
|
|
2125
|
-
<pre class="k-lang"><code>$bool = < {} true, {} false >;
|
|
2126
|
-
neg = $bool < /true | false, /false | true > $bool;</code></pre>
|
|
2127
|
-
<ol type="1">
|
|
2128
|
-
<li><p><strong>Parsing:</strong> The compiler recognizes a type
|
|
2129
|
-
definition <code>$bool</code> and a function <code>neg</code>.</p></li>
|
|
2130
|
-
<li><p><strong>Type analysis:</strong> Both the input and output of
|
|
2131
|
-
<code>neg</code> are of type <code>bool</code>.</p></li>
|
|
2132
|
-
<li><p><strong>Internal representation:</strong> The compiler constructs
|
|
2133
|
-
an internal tree describing that
|
|
2134
|
-
<code>< /true f₁, /false f₂ ></code> means: try the projection
|
|
2135
|
-
<code>/true</code>, then <code>/false</code>, each producing a constant
|
|
2136
|
-
value.</p></li>
|
|
2137
|
-
<li><p><strong>Generated form:</strong> In the target language,
|
|
2138
|
-
<code>neg</code> becomes a small function that:</p>
|
|
2139
|
-
<ul>
|
|
2140
|
-
<li>calls <code>k_project</code> to check which variant the input
|
|
2141
|
-
has,</li>
|
|
2142
|
-
<li>creates a new node with the opposite variant using
|
|
2143
|
-
<code>k_make_union</code>, and</li>
|
|
2144
|
-
<li>returns the result with <code>ok = 1</code>.</li>
|
|
2145
|
-
</ul></li>
|
|
2146
|
-
</ol>
|
|
2147
|
-
<p>This sequence of steps is fully automatic and follows directly from
|
|
2148
|
-
the semantic rules in Chapter 8.</p>
|
|
2149
|
-
<hr />
|
|
2150
|
-
<h2 id="intermediate-representation"><strong>9.6 Intermediate
|
|
2151
|
-
representation</strong></h2>
|
|
2152
|
-
<p>Before producing final code, many compilers use an <em>intermediate
|
|
2153
|
-
representation</em> (IR). It is a language designed to be easy to
|
|
2154
|
-
generate and easy to translate further into real machine code. For
|
|
2155
|
-
<code>k</code>, the IR mirrors the structure of partial functions:</p>
|
|
2156
|
-
<table>
|
|
2157
|
-
<thead>
|
|
2158
|
-
<tr>
|
|
2159
|
-
<th>Concept in k</th>
|
|
2160
|
-
<th>IR operation</th>
|
|
2161
|
-
</tr>
|
|
2162
|
-
</thead>
|
|
2163
|
-
<tbody>
|
|
2164
|
-
<tr>
|
|
2165
|
-
<td>Projection <code>.x</code> ‘/x’</td>
|
|
2166
|
-
<td><code>PROJECT label_id</code></td>
|
|
2167
|
-
</tr>
|
|
2168
|
-
<tr>
|
|
2169
|
-
<td>Composition <code>(f g)</code></td>
|
|
2170
|
-
<td><code>CALL f; CALL g</code></td>
|
|
2171
|
-
</tr>
|
|
2172
|
-
<tr>
|
|
2173
|
-
<td>Union <code><f,g></code></td>
|
|
2174
|
-
<td><code>TRY f; IF undefined THEN TRY g</code></td>
|
|
2175
|
-
</tr>
|
|
2176
|
-
<tr>
|
|
2177
|
-
<td>Product <code>{.x f, .y g}</code></td>
|
|
2178
|
-
<td><code>PRODUCT_CALL (f, g); COMBINE</code></td>
|
|
2179
|
-
</tr>
|
|
2180
|
-
<tr>
|
|
2181
|
-
<td>Type restriction <code>$T</code></td>
|
|
2182
|
-
<td><code>CHECK_TYPE state_id</code></td>
|
|
2183
|
-
</tr>
|
|
2184
|
-
</tbody>
|
|
2185
|
-
</table>
|
|
2186
|
-
<p>The compiler converts each AST node into one or more IR instructions.
|
|
2187
|
-
The <code>PRODUCT_CALL(f, g)</code> instruction is a higher-level
|
|
2188
|
-
concept that implies applying both <code>f</code> and <code>g</code> to
|
|
2189
|
-
the same input value. The low-level implementation of this would use
|
|
2190
|
-
stack operations to duplicate the input, but the IR itself remains more
|
|
2191
|
-
abstract. Later, these instructions are translated into LLVM or C code
|
|
2192
|
-
using the runtime ABI.</p>
|
|
2193
|
-
<hr />
|
|
2194
|
-
<h2 id="linking-with-the-runtime"><strong>9.7 Linking with the
|
|
2195
|
-
runtime</strong></h2>
|
|
2196
|
-
<p>The generated code does not contain memory allocation or type tables
|
|
2197
|
-
itself. Instead, it relies on the runtime library (<code>krt</code>),
|
|
2198
|
-
which provides:</p>
|
|
2199
|
-
<ul>
|
|
2200
|
-
<li>functions such as <code>k_project</code> and
|
|
2201
|
-
<code>k_make_union</code>,</li>
|
|
2202
|
-
<li>metadata tables for each canonical type, and</li>
|
|
2203
|
-
<li>the unit value <code>{}</code> shared by all programs.</li>
|
|
2204
|
-
</ul>
|
|
2205
|
-
<p>When the compiler finishes, it outputs a text file in the target
|
|
2206
|
-
language plus references to this runtime library. The two together form
|
|
2207
|
-
an executable program.</p>
|
|
2208
|
-
<hr />
|
|
2209
|
-
<h2 id="simplicity-of-the-model"><strong>9.8 Simplicity of the
|
|
2210
|
-
model</strong></h2>
|
|
2211
|
-
<p>Because every expression in <code>k</code> takes exactly one input
|
|
2212
|
-
and may return one output or be undefined, the compiler never has to
|
|
2213
|
-
deal with variable environments, loops, or side effects. This makes the
|
|
2214
|
-
structure of the generated program very regular:</p>
|
|
2215
|
-
<pre class="text"><code>input → [series of calls and checks] → output or undefined</code></pre>
|
|
2216
|
-
<p>Each compiled function is independent and stateless. This regularity
|
|
2217
|
-
is what allows <code>k</code> to map cleanly to low-level code.</p>
|
|
2218
|
-
<hr />
|
|
2219
|
-
<h2 id="summary-7"><strong>9.9 Summary</strong></h2>
|
|
2220
|
-
<ul>
|
|
2221
|
-
<li>The compiler transforms <code>k</code> programs into executable form
|
|
2222
|
-
through a sequence of simple, deterministic steps.</li>
|
|
2223
|
-
<li>Type information and structure are resolved before code
|
|
2224
|
-
generation.</li>
|
|
2225
|
-
<li>All generated functions follow the same calling convention
|
|
2226
|
-
(<code>ok</code>, <code>val</code>).</li>
|
|
2227
|
-
<li>The runtime library provides the shared operations needed by every
|
|
2228
|
-
program.</li>
|
|
2229
|
-
<li>The entire process mirrors the formal semantics defined earlier but
|
|
2230
|
-
expresses it as concrete machine operations.</li>
|
|
2231
|
-
</ul>
|
|
2232
|
-
<hr />
|
|
2233
|
-
<hr />
|
|
2234
|
-
<h1 id="chapter-10-from-ast-to-intermediate-representation">Chapter 10 —
|
|
2235
|
-
From AST to Intermediate Representation</h1>
|
|
2236
|
-
<h2 id="the-purpose-of-an-intermediate-form"><strong>10.1 The purpose of
|
|
2237
|
-
an intermediate form</strong></h2>
|
|
2238
|
-
<p>The abstract syntax tree (AST) of a <code>k</code> program directly
|
|
2239
|
-
reflects how the source code was written. It is easy to read but not
|
|
2240
|
-
convenient for generating machine code. Before code can be produced, the
|
|
2241
|
-
compiler rewrites this tree into a <strong>simpler, regular
|
|
2242
|
-
structure</strong> called the <em>intermediate representation</em>
|
|
2243
|
-
(IR).</p>
|
|
2244
|
-
<p>The IR is close to what the machine will execute, but it still looks
|
|
2245
|
-
like a structured program rather than raw binary instructions. Each node
|
|
2246
|
-
in the IR corresponds to a single, well-defined operation such as
|
|
2247
|
-
<em>project a field</em>, <em>apply a function</em>, or <em>combine
|
|
2248
|
-
results</em>.</p>
|
|
2249
|
-
<p>Using an intermediate form helps in three ways:</p>
|
|
2250
|
-
<ol type="1">
|
|
2251
|
-
<li>It separates understanding of the language from machine
|
|
2252
|
-
details.</li>
|
|
2253
|
-
<li>It allows the compiler to verify that every function is well
|
|
2254
|
-
formed.</li>
|
|
2255
|
-
<li>It provides a uniform surface for optimization and for later
|
|
2256
|
-
translation into C or LLVM.</li>
|
|
2257
|
-
</ol>
|
|
2258
|
-
<hr />
|
|
2259
|
-
<h2 id="shape-of-the-intermediate-representation"><strong>10.2 Shape of
|
|
2260
|
-
the intermediate representation</strong></h2>
|
|
2261
|
-
<p>Each IR instruction corresponds to one semantic rule from Chapter 8.
|
|
2262
|
-
The IR does not need to represent filters or meta-variables, since those
|
|
2263
|
-
are resolved earlier. Only concrete actions remain.</p>
|
|
2264
|
-
<table>
|
|
2265
|
-
<colgroup>
|
|
2266
|
-
<col style="width: 31%" />
|
|
2267
|
-
<col style="width: 68%" />
|
|
2268
|
-
</colgroup>
|
|
2269
|
-
<thead>
|
|
2270
|
-
<tr>
|
|
2271
|
-
<th>Operation</th>
|
|
2272
|
-
<th>Meaning</th>
|
|
2273
|
-
</tr>
|
|
2274
|
-
</thead>
|
|
2275
|
-
<tbody>
|
|
2276
|
-
<tr>
|
|
2277
|
-
<td><strong>PROJECT label_id</strong></td>
|
|
2278
|
-
<td>Apply <code>.label</code> to the input value.</td>
|
|
2279
|
-
</tr>
|
|
2280
|
-
<tr>
|
|
2281
|
-
<td><strong>TYPECHECK state_id</strong></td>
|
|
2282
|
-
<td>Accept the input only if its root has the given canonical
|
|
2283
|
-
state.</td>
|
|
2284
|
-
</tr>
|
|
2285
|
-
<tr>
|
|
2286
|
-
<td><strong>CALL function_id</strong></td>
|
|
2287
|
-
<td>Invoke another function following the ABI.</td>
|
|
2288
|
-
</tr>
|
|
2289
|
-
<tr>
|
|
2290
|
-
<td><strong>UNION [f₁, f₂, …]</strong></td>
|
|
2291
|
-
<td>Try several functions in order until one succeeds.</td>
|
|
2292
|
-
</tr>
|
|
2293
|
-
<tr>
|
|
2294
|
-
<td><strong>PRODUCT [l₁=f₁, l₂=f₂, …]</strong></td>
|
|
2295
|
-
<td>Apply each function to the same input and combine results.</td>
|
|
2296
|
-
</tr>
|
|
2297
|
-
<tr>
|
|
2298
|
-
<td><strong>FAIL</strong></td>
|
|
2299
|
-
<td>Always undefined.</td>
|
|
2300
|
-
</tr>
|
|
2301
|
-
<tr>
|
|
2302
|
-
<td><strong>SEQ [f₁, f₂, …]</strong></td>
|
|
2303
|
-
<td>Apply functions in sequence (composition).</td>
|
|
2304
|
-
</tr>
|
|
2305
|
-
</tbody>
|
|
2306
|
-
</table>
|
|
2307
|
-
<p>Each function in the program becomes a small list or tree of such IR
|
|
2308
|
-
instructions.</p>
|
|
2309
|
-
<hr />
|
|
2310
|
-
<h2 id="example-2"><strong>10.3 Example</strong></h2>
|
|
2311
|
-
<p>Source program:</p>
|
|
2312
|
-
<pre class="k-lang"><code>$bool = < {} true, {} false >;
|
|
2313
|
-
neg = $bool < .true {{ } false}, .false {{ } true} > $bool;</code></pre>
|
|
2314
|
-
<p>The IR for <code>neg</code> can be written informally as:</p>
|
|
2315
|
-
<pre class="text"><code>neg:
|
|
2316
|
-
TYPECHECK bool
|
|
2317
|
-
UNION [
|
|
2318
|
-
SEQ [ PROJECT true, CONST false ],
|
|
2319
|
-
SEQ [ PROJECT false, CONST true ]
|
|
2320
|
-
]
|
|
2321
|
-
TYPECHECK bool</code></pre>
|
|
2322
|
-
<p>This IR expresses the same logic as the source: check the type, then
|
|
2323
|
-
try the first projection <code>.true</code>, otherwise the second, and
|
|
2324
|
-
finally ensure the result is again of type <code>$bool</code>.</p>
|
|
2325
|
-
<hr />
|
|
2326
|
-
<h2 id="relation-to-evaluation"><strong>10.4 Relation to
|
|
2327
|
-
evaluation</strong></h2>
|
|
2328
|
-
<p>Every IR operation corresponds to a runtime action:</p>
|
|
2329
|
-
<table>
|
|
2330
|
-
<thead>
|
|
2331
|
-
<tr>
|
|
2332
|
-
<th>IR operation</th>
|
|
2333
|
-
<th>Runtime function or behavior</th>
|
|
2334
|
-
</tr>
|
|
2335
|
-
</thead>
|
|
2336
|
-
<tbody>
|
|
2337
|
-
<tr>
|
|
2338
|
-
<td>PROJECT</td>
|
|
2339
|
-
<td><code>k_project(input, label_id)</code></td>
|
|
2340
|
-
</tr>
|
|
2341
|
-
<tr>
|
|
2342
|
-
<td>TYPECHECK</td>
|
|
2343
|
-
<td>verify <code>input->state == state_id</code></td>
|
|
2344
|
-
</tr>
|
|
2345
|
-
<tr>
|
|
2346
|
-
<td>CALL</td>
|
|
2347
|
-
<td>call another generated function</td>
|
|
2348
|
-
</tr>
|
|
2349
|
-
<tr>
|
|
2350
|
-
<td>UNION</td>
|
|
2351
|
-
<td>sequential <code>if</code>–<code>else</code> test on success
|
|
2352
|
-
flags</td>
|
|
2353
|
-
</tr>
|
|
2354
|
-
<tr>
|
|
2355
|
-
<td>PRODUCT</td>
|
|
2356
|
-
<td>multiple subcalls + <code>k_make_product</code></td>
|
|
2357
|
-
</tr>
|
|
2358
|
-
<tr>
|
|
2359
|
-
<td>FAIL</td>
|
|
2360
|
-
<td>return <code>{ ok = 0 }</code> immediately</td>
|
|
2361
|
-
</tr>
|
|
2362
|
-
<tr>
|
|
2363
|
-
<td>SEQ</td>
|
|
2364
|
-
<td>connect the output of one step as input to the next</td>
|
|
2365
|
-
</tr>
|
|
2366
|
-
</tbody>
|
|
2367
|
-
</table>
|
|
2368
|
-
<p>By describing computation in these terms, the compiler can generate
|
|
2369
|
-
executable code simply by replacing each IR instruction with its runtime
|
|
2370
|
-
equivalent.</p>
|
|
2371
|
-
<hr />
|
|
2372
|
-
<h2 id="building-the-ir"><strong>10.5 Building the IR</strong></h2>
|
|
2373
|
-
<p>The process of converting the AST to IR follows a recursive
|
|
2374
|
-
pattern:</p>
|
|
2375
|
-
<ol type="1">
|
|
2376
|
-
<li><strong>Projections</strong> become single instructions
|
|
2377
|
-
<code>PROJECT</code>.</li>
|
|
2378
|
-
<li><strong>Compositions</strong> <code>(f g h)</code> become a
|
|
2379
|
-
<code>SEQ</code> list of their components.</li>
|
|
2380
|
-
<li><strong>Unions</strong> <code><f,g></code> become a
|
|
2381
|
-
<code>UNION</code> list.</li>
|
|
2382
|
-
<li><strong>Products</strong> <code>{f l₁, g l₂}</code> become a
|
|
2383
|
-
<code>PRODUCT</code> list with labeled entries.</li>
|
|
2384
|
-
<li><strong>Type expressions</strong> <code>$T</code> become
|
|
2385
|
-
<code>TYPECHECK</code> instructions.</li>
|
|
2386
|
-
<li><strong>Filters</strong> disappear; their meaning is already
|
|
2387
|
-
captured by typechecks.</li>
|
|
2388
|
-
</ol>
|
|
2389
|
-
<p>Each transformation step produces IR nodes with fixed behavior and
|
|
2390
|
-
explicit order.</p>
|
|
2391
|
-
<hr />
|
|
2392
|
-
<h2 id="verifying-the-ir"><strong>10.6 Verifying the IR</strong></h2>
|
|
2393
|
-
<p>Because k programs are defined by simple composition, a small set of
|
|
2394
|
-
checks ensures correctness:</p>
|
|
2395
|
-
<ol type="1">
|
|
2396
|
-
<li>Each <code>UNION</code> list must have at least one element.</li>
|
|
2397
|
-
<li>Every <code>PROJECT</code> must have a valid label.</li>
|
|
2398
|
-
<li>Input and output states of consecutive steps must match.</li>
|
|
2399
|
-
<li>A function must end in an operation that produces a result
|
|
2400
|
-
(<code>PROJECT</code>, <code>CALL</code>, or combination).</li>
|
|
2401
|
-
</ol>
|
|
2402
|
-
<p>After verification, the IR is guaranteed to represent a valid partial
|
|
2403
|
-
function according to the semantics in Chapter 8.</p>
|
|
2404
|
-
<hr />
|
|
2405
|
-
<h2 id="intermediate-form-as-a-small-language"><strong>10.7 Intermediate
|
|
2406
|
-
form as a small language</strong></h2>
|
|
2407
|
-
<p>The IR can be viewed as a minimal language on its own. It has:</p>
|
|
2408
|
-
<ul>
|
|
2409
|
-
<li>one data type (<code>KNode*</code>),</li>
|
|
2410
|
-
<li>one universal value format (trees),</li>
|
|
2411
|
-
<li>and a fixed set of operators.</li>
|
|
2412
|
-
</ul>
|
|
2413
|
-
<p>Its execution model is the same as the runtime ABI. This means an
|
|
2414
|
-
interpreter for the IR can serve as a reference implementation of the k
|
|
2415
|
-
semantics before any machine code generation is added.</p>
|
|
2416
|
-
<hr />
|
|
2417
|
-
<h2 id="example-product-composition"><strong>10.8 Example: product
|
|
2418
|
-
composition</strong></h2>
|
|
2419
|
-
<p>For input function <code>{ .x a, .y b }</code>, the IR is:</p>
|
|
2420
|
-
<pre class="text"><code>PRODUCT [
|
|
2421
|
-
a = PROJECT x,
|
|
2422
|
-
b = PROJECT y
|
|
2423
|
-
]</code></pre>
|
|
2424
|
-
<p>The runtime sequence is:</p>
|
|
2425
|
-
<ol type="1">
|
|
2426
|
-
<li>Apply each projection.</li>
|
|
2427
|
-
<li>If both succeed, build a new node with two children in order
|
|
2428
|
-
<code>(a,b)</code>.</li>
|
|
2429
|
-
</ol>
|
|
2430
|
-
<p>This pattern covers all record-building operations in the
|
|
2431
|
-
language.</p>
|
|
2432
|
-
<hr />
|
|
2433
|
-
<h2 id="why-this-representation-is-useful"><strong>10.9 Why this
|
|
2434
|
-
representation is useful</strong></h2>
|
|
2435
|
-
<p>This intermediate form provides three practical benefits:</p>
|
|
2436
|
-
<ol type="1">
|
|
2437
|
-
<li><strong>Clarity</strong> – every step is explicit and local.</li>
|
|
2438
|
-
<li><strong>Verifiability</strong> – type consistency and definedness
|
|
2439
|
-
can be checked mechanically.</li>
|
|
2440
|
-
<li><strong>Flexibility</strong> – the same IR can be translated to many
|
|
2441
|
-
targets (LLVM IR, C, or even interpreted directly).</li>
|
|
2442
|
-
</ol>
|
|
2443
|
-
<p>Because of these advantages, most compilers for declarative languages
|
|
2444
|
-
use an intermediate form of this kind.</p>
|
|
2445
|
-
<hr />
|
|
2446
|
-
<h2 id="summary-8"><strong>10.10 Summary</strong></h2>
|
|
2447
|
-
<ul>
|
|
2448
|
-
<li>The abstract syntax tree is rewritten into a simpler,
|
|
2449
|
-
machine-oriented form.</li>
|
|
2450
|
-
<li>Each IR instruction represents one operation defined by the
|
|
2451
|
-
<code>k</code> semantics.</li>
|
|
2452
|
-
<li>Type and filter information appear as explicit checks.</li>
|
|
2453
|
-
<li>The IR is easy to verify and to translate into executable code.</li>
|
|
2454
|
-
<li>The IR can also serve as a precise description of how <code>k</code>
|
|
2455
|
-
functions behave step by step.</li>
|
|
2456
|
-
</ul>
|
|
2457
|
-
<hr />
|
|
2458
|
-
<hr />
|
|
2459
|
-
<h1 id="chapter-11-llvm-basics">Chapter 11 — LLVM Basics</h1>
|
|
2460
|
-
<h2 id="purpose-2"><strong>11.1 Purpose</strong></h2>
|
|
2461
|
-
<p>The previous chapters described how a <code>k</code> program can be
|
|
2462
|
-
reduced to a small set of intermediate operations. To execute these
|
|
2463
|
-
operations efficiently, the compiler must translate them into an actual
|
|
2464
|
-
machine language. Instead of generating raw machine code directly, we
|
|
2465
|
-
use a common intermediate format called <strong>LLVM IR</strong> (LLVM
|
|
2466
|
-
<em>Intermediate Representation</em>).</p>
|
|
2467
|
-
<p>LLVM IR is a low-level, strongly typed language that resembles a
|
|
2468
|
-
simplified form of assembly. It can be read and written as text,
|
|
2469
|
-
analyzed, optimized, and compiled to machine code for almost any
|
|
2470
|
-
processor. For the compiler writer, it provides a bridge between
|
|
2471
|
-
high-level language semantics and executable programs.</p>
|
|
2472
|
-
<hr />
|
|
2473
|
-
<h2 id="structure-of-an-llvm-program"><strong>11.2 Structure of an LLVM
|
|
2474
|
-
program</strong></h2>
|
|
2475
|
-
<p>An LLVM program consists of <strong>global definitions</strong> and
|
|
2476
|
-
<strong>functions</strong>.</p>
|
|
2477
|
-
<ul>
|
|
2478
|
-
<li><p><em>Global definitions</em> describe data structures shared
|
|
2479
|
-
between functions. In the <code>k</code> compiler, this includes the
|
|
2480
|
-
runtime metadata tables and constant nodes such as
|
|
2481
|
-
<code>{}</code>.</p></li>
|
|
2482
|
-
<li><p><em>Functions</em> contain sequences of instructions grouped into
|
|
2483
|
-
<strong>basic blocks</strong>. A basic block is a straight-line segment
|
|
2484
|
-
of code with no branches except at the end. Branches connect blocks,
|
|
2485
|
-
forming a control-flow graph.</p></li>
|
|
2486
|
-
</ul>
|
|
2487
|
-
<p>Each instruction produces a new value; values are immutable once
|
|
2488
|
-
created. This property is called <em>single static assignment</em>
|
|
2489
|
-
(SSA).</p>
|
|
2490
|
-
<hr />
|
|
2491
|
-
<h2 id="data-types"><strong>11.3 Data types</strong></h2>
|
|
2492
|
-
<p>LLVM provides several primitive types. Only a few are required for
|
|
2493
|
-
the <code>k</code> compiler:</p>
|
|
2494
|
-
<table>
|
|
2495
|
-
<thead>
|
|
2496
|
-
<tr>
|
|
2497
|
-
<th>LLVM type</th>
|
|
2498
|
-
<th>Meaning</th>
|
|
2499
|
-
</tr>
|
|
2500
|
-
</thead>
|
|
2501
|
-
<tbody>
|
|
2502
|
-
<tr>
|
|
2503
|
-
<td><code>i1</code></td>
|
|
2504
|
-
<td>one-bit boolean (used for success flag)</td>
|
|
2505
|
-
</tr>
|
|
2506
|
-
<tr>
|
|
2507
|
-
<td><code>i32</code></td>
|
|
2508
|
-
<td>32-bit integer (used for state IDs, indices, tags)</td>
|
|
2509
|
-
</tr>
|
|
2510
|
-
<tr>
|
|
2511
|
-
<td><code>ptr</code> or <code>%T*</code></td>
|
|
2512
|
-
<td>pointer to data in memory</td>
|
|
2513
|
-
</tr>
|
|
2514
|
-
<tr>
|
|
2515
|
-
<td><code>%struct {...}</code></td>
|
|
2516
|
-
<td>user-defined record (used for <code>KNode</code> and
|
|
2517
|
-
<code>KOpt</code>)</td>
|
|
2518
|
-
</tr>
|
|
2519
|
-
</tbody>
|
|
2520
|
-
</table>
|
|
2521
|
-
<p>The main structures used by generated code are:</p>
|
|
2522
|
-
<div class="sourceCode" id="cb90"><pre
|
|
2523
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%KNode</span> = <span class="kw">type</span> { <span class="dt">i32</span>, <span class="dt">i32</span>, <span class="dt">i32</span>, [<span class="dv">0</span> x <span class="fu">%KNode</span>*] }</span>
|
|
2524
|
-
<span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%KVal</span> = <span class="kw">type</span> { <span class="fu">%KNode</span>* }</span>
|
|
2525
|
-
<span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a><span class="fu">%KOpt</span> = <span class="kw">type</span> { <span class="dt">i1</span>, <span class="fu">%KVal</span> }</span></code></pre></div>
|
|
2526
|
-
<p><code>%KNode</code> represents one tree node in memory;
|
|
2527
|
-
<code>%KOpt</code> represents the result of a partial function, with an
|
|
2528
|
-
<code>ok</code> flag and a value pointer.</p>
|
|
2529
|
-
<hr />
|
|
2530
|
-
<h2 id="function-signatures"><strong>11.4 Function
|
|
2531
|
-
signatures</strong></h2>
|
|
2532
|
-
<p>Every compiled <code>k</code> function is translated into one LLVM
|
|
2533
|
-
function with the following signature:</p>
|
|
2534
|
-
<div class="sourceCode" id="cb91"><pre
|
|
2535
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb91-1"><a href="#cb91-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@f_name</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>) { ... }</span></code></pre></div>
|
|
2536
|
-
<p>The function takes a single argument <code>%in</code>, which holds
|
|
2537
|
-
the pointer to the input value. It returns a <code>%KOpt</code>
|
|
2538
|
-
structure containing the success flag and the resulting value.</p>
|
|
2539
|
-
<p>This mirrors the runtime ABI introduced in Chapter 7. By using the
|
|
2540
|
-
same layout, all functions can call each other without conversions.</p>
|
|
2541
|
-
<hr />
|
|
2542
|
-
<h2 id="control-flow"><strong>11.5 Control flow</strong></h2>
|
|
2543
|
-
<p>LLVM IR uses <strong>conditional branches</strong> to express choices
|
|
2544
|
-
and <strong>phi-nodes</strong> to merge results from different
|
|
2545
|
-
paths.</p>
|
|
2546
|
-
<p>A typical pattern for union composition <code><f,g></code>
|
|
2547
|
-
is:</p>
|
|
2548
|
-
<div class="sourceCode" id="cb92"><pre
|
|
2549
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb92-1"><a href="#cb92-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@f</span>(<span class="fu">%in</span>)</span>
|
|
2550
|
-
<span id="cb92-2"><a href="#cb92-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
|
|
2551
|
-
<span id="cb92-3"><a href="#cb92-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%success</span>, <span class="dt">label</span> <span class="fu">%try_next</span></span>
|
|
2552
|
-
<span id="cb92-4"><a href="#cb92-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
2553
|
-
<span id="cb92-5"><a href="#cb92-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_next:</span></span>
|
|
2554
|
-
<span id="cb92-6"><a href="#cb92-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@g</span>(<span class="fu">%in</span>)</span>
|
|
2555
|
-
<span id="cb92-7"><a href="#cb92-7" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
|
|
2556
|
-
<span id="cb92-8"><a href="#cb92-8" aria-hidden="true" tabindex="-1"></a></span>
|
|
2557
|
-
<span id="cb92-9"><a href="#cb92-9" aria-hidden="true" tabindex="-1"></a><span class="fu">success:</span></span>
|
|
2558
|
-
<span id="cb92-10"><a href="#cb92-10" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
|
|
2559
|
-
<span id="cb92-11"><a href="#cb92-11" aria-hidden="true" tabindex="-1"></a></span>
|
|
2560
|
-
<span id="cb92-12"><a href="#cb92-12" aria-hidden="true" tabindex="-1"></a><span class="fu">merge:</span></span>
|
|
2561
|
-
<span id="cb92-13"><a href="#cb92-13" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">phi</span> <span class="fu">%KOpt</span> [ <span class="fu">%r1</span>, <span class="fu">%success</span> ], [ <span class="fu">%r2</span>, <span class="fu">%try_next</span> ]</span>
|
|
2562
|
-
<span id="cb92-14"><a href="#cb92-14" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%res</span></span></code></pre></div>
|
|
2563
|
-
<p>This code means: try <code>f</code>; if it succeeds, use that result;
|
|
2564
|
-
otherwise, try <code>g</code>. The <code>phi</code> instruction chooses
|
|
2565
|
-
between values coming from different blocks.</p>
|
|
2566
|
-
<hr />
|
|
2567
|
-
<h2 id="memory-operations"><strong>11.6 Memory operations</strong></h2>
|
|
2568
|
-
<p>Most functions in k do not modify existing nodes; they create new
|
|
2569
|
-
ones. Node creation is implemented as calls to runtime functions:</p>
|
|
2570
|
-
<div class="sourceCode" id="cb93"><pre
|
|
2571
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb93-1"><a href="#cb93-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%n</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
|
|
2572
|
-
<span id="cb93-2"><a href="#cb93-2" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_union</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%tag</span>, <span class="fu">%KVal</span> <span class="fu">%child</span>)</span></code></pre></div>
|
|
2573
|
-
<p>These calls allocate new immutable nodes. The compiler provides the
|
|
2574
|
-
correct <code>state</code>, <code>tag</code>, and child references
|
|
2575
|
-
according to the canonical type.</p>
|
|
2576
|
-
<hr />
|
|
2577
|
-
<h2 id="constants-1"><strong>11.7 Constants</strong></h2>
|
|
2578
|
-
<p>Constant values such as <code>{{} true}</code> are represented as
|
|
2579
|
-
global variables in LLVM:</p>
|
|
2580
|
-
<div class="sourceCode" id="cb94"><pre
|
|
2581
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb94-1"><a href="#cb94-1" aria-hidden="true" tabindex="-1"></a><span class="fu">@unit_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">1</span>, -<span class="dv">1</span>, <span class="dv">0</span>, [] }</span>
|
|
2582
|
-
<span id="cb94-2"><a href="#cb94-2" aria-hidden="true" tabindex="-1"></a><span class="fu">@true_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, [<span class="fu">@unit_node</span>] }</span>
|
|
2583
|
-
<span id="cb94-3"><a href="#cb94-3" aria-hidden="true" tabindex="-1"></a><span class="fu">@false_node</span> = <span class="kw">constant</span> <span class="fu">%KNode</span> { <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">1</span>, [<span class="fu">@unit_node</span>] }</span></code></pre></div>
|
|
2584
|
-
<p>Each constant is a fully formed node with fixed fields. When a
|
|
2585
|
-
constant function is called, the compiler returns a pointer to the
|
|
2586
|
-
corresponding global node.</p>
|
|
2587
|
-
<hr />
|
|
2588
|
-
<h2 id="from-ir-to-llvm"><strong>11.8 From IR to LLVM</strong></h2>
|
|
2589
|
-
<p>Translating the compiler’s intermediate form (Chapter 10) into LLVM
|
|
2590
|
-
is mechanical:</p>
|
|
2591
|
-
<table>
|
|
2592
|
-
<colgroup>
|
|
2593
|
-
<col style="width: 18%" />
|
|
2594
|
-
<col style="width: 81%" />
|
|
2595
|
-
</colgroup>
|
|
2596
|
-
<thead>
|
|
2597
|
-
<tr>
|
|
2598
|
-
<th>IR operation</th>
|
|
2599
|
-
<th>LLVM translation</th>
|
|
2600
|
-
</tr>
|
|
2601
|
-
</thead>
|
|
2602
|
-
<tbody>
|
|
2603
|
-
<tr>
|
|
2604
|
-
<td><code>PROJECT</code></td>
|
|
2605
|
-
<td>call <code>@k_project</code></td>
|
|
2606
|
-
</tr>
|
|
2607
|
-
<tr>
|
|
2608
|
-
<td><code>TYPECHECK</code></td>
|
|
2609
|
-
<td>compare <code>input->state</code> with constant</td>
|
|
2610
|
-
</tr>
|
|
2611
|
-
<tr>
|
|
2612
|
-
<td><code>CONST</code></td>
|
|
2613
|
-
<td>return constant node</td>
|
|
2614
|
-
</tr>
|
|
2615
|
-
<tr>
|
|
2616
|
-
<td><code>PRODUCT</code></td>
|
|
2617
|
-
<td>evaluate subcalls, check flags, call
|
|
2618
|
-
<code>@k_make_product</code></td>
|
|
2619
|
-
</tr>
|
|
2620
|
-
<tr>
|
|
2621
|
-
<td><code>UNION</code></td>
|
|
2622
|
-
<td>generate branching structure as above</td>
|
|
2623
|
-
</tr>
|
|
2624
|
-
<tr>
|
|
2625
|
-
<td><code>SEQ</code></td>
|
|
2626
|
-
<td>chain calls: feed output to next input</td>
|
|
2627
|
-
</tr>
|
|
2628
|
-
<tr>
|
|
2629
|
-
<td><code>FAIL</code></td>
|
|
2630
|
-
<td>return <code>%KOpt { 0, undef }</code></td>
|
|
2631
|
-
</tr>
|
|
2632
|
-
</tbody>
|
|
2633
|
-
</table>
|
|
2634
|
-
<p>These mappings produce correct, low-level code while remaining
|
|
2635
|
-
faithful to the language semantics.</p>
|
|
2636
|
-
<hr />
|
|
2637
|
-
<h2 id="example-3"><strong>11.9 Example</strong></h2>
|
|
2638
|
-
<p>For the function <code>neg</code> from earlier:</p>
|
|
2639
|
-
<pre class="k-lang"><code>$bool = < {} true, {} false >;
|
|
2640
|
-
neg = $bool < .true {{ } false}, .false {{ } true} > $bool;</code></pre>
|
|
2641
|
-
<p>The simplified LLVM version may look as follows (comments added):</p>
|
|
2642
|
-
<div class="sourceCode" id="cb96"><pre
|
|
2643
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb96-1"><a href="#cb96-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@neg</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>) {</span>
|
|
2644
|
-
<span id="cb96-2"><a href="#cb96-2" aria-hidden="true" tabindex="-1"></a><span class="fu">entry:</span></span>
|
|
2645
|
-
<span id="cb96-3"><a href="#cb96-3" aria-hidden="true" tabindex="-1"></a> <span class="co">; Try the .true branch</span></span>
|
|
2646
|
-
<span id="cb96-4"><a href="#cb96-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@project_true</span>(<span class="fu">%in</span>)</span>
|
|
2647
|
-
<span id="cb96-5"><a href="#cb96-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
|
|
2648
|
-
<span id="cb96-6"><a href="#cb96-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%case_true</span>, <span class="dt">label</span> <span class="fu">%case_false</span></span>
|
|
2649
|
-
<span id="cb96-7"><a href="#cb96-7" aria-hidden="true" tabindex="-1"></a></span>
|
|
2650
|
-
<span id="cb96-8"><a href="#cb96-8" aria-hidden="true" tabindex="-1"></a><span class="fu">case_true:</span></span>
|
|
2651
|
-
<span id="cb96-9"><a href="#cb96-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_true</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="kw">undef</span>, <span class="dt">i1</span> <span class="dv">1</span>, <span class="dv">0</span></span>
|
|
2652
|
-
<span id="cb96-10"><a href="#cb96-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_true2</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="fu">%res_true</span>, <span class="fu">%KVal</span> <span class="fu">@false_node</span>, <span class="dv">1</span></span>
|
|
2653
|
-
<span id="cb96-11"><a href="#cb96-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res_true2</span></span>
|
|
2654
|
-
<span id="cb96-12"><a href="#cb96-12" aria-hidden="true" tabindex="-1"></a></span>
|
|
2655
|
-
<span id="cb96-13"><a href="#cb96-13" aria-hidden="true" tabindex="-1"></a><span class="fu">case_false:</span></span>
|
|
2656
|
-
<span id="cb96-14"><a href="#cb96-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@project_false</span>(<span class="fu">%in</span>)</span>
|
|
2657
|
-
<span id="cb96-15"><a href="#cb96-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">%ok2</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r2</span>, <span class="dv">0</span></span>
|
|
2658
|
-
<span id="cb96-16"><a href="#cb96-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok2</span>, <span class="dt">label</span> <span class="fu">%case_false_valid</span>, <span class="dt">label</span> <span class="fu">%undefined</span></span>
|
|
2659
|
-
<span id="cb96-17"><a href="#cb96-17" aria-hidden="true" tabindex="-1"></a></span>
|
|
2660
|
-
<span id="cb96-18"><a href="#cb96-18" aria-hidden="true" tabindex="-1"></a><span class="fu">case_false_valid:</span></span>
|
|
2661
|
-
<span id="cb96-19"><a href="#cb96-19" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_false</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="kw">undef</span>, <span class="dt">i1</span> <span class="dv">1</span>, <span class="dv">0</span></span>
|
|
2662
|
-
<span id="cb96-20"><a href="#cb96-20" aria-hidden="true" tabindex="-1"></a> <span class="fu">%res_false2</span> = <span class="kw">insertvalue</span> <span class="fu">%KOpt</span> <span class="fu">%res_false</span>, <span class="fu">%KVal</span> <span class="fu">@true_node</span>, <span class="dv">1</span></span>
|
|
2663
|
-
<span id="cb96-21"><a href="#cb96-21" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res_false2</span></span>
|
|
2664
|
-
<span id="cb96-22"><a href="#cb96-22" aria-hidden="true" tabindex="-1"></a></span>
|
|
2665
|
-
<span id="cb96-23"><a href="#cb96-23" aria-hidden="true" tabindex="-1"></a><span class="fu">undefined:</span></span>
|
|
2666
|
-
<span id="cb96-24"><a href="#cb96-24" aria-hidden="true" tabindex="-1"></a> <span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span>
|
|
2667
|
-
<span id="cb96-25"><a href="#cb96-25" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
|
2668
|
-
<p>While verbose, this code mirrors the evaluation rules exactly and can
|
|
2669
|
-
be optimized by standard LLVM tools.</p>
|
|
2670
|
-
<hr />
|
|
2671
|
-
<h2 id="optimization-and-verification"><strong>11.10 Optimization and
|
|
2672
|
-
verification</strong></h2>
|
|
2673
|
-
<p>LLVM provides built-in passes that simplify generated code:</p>
|
|
2674
|
-
<ul>
|
|
2675
|
-
<li><strong>mem2reg</strong> — removes unnecessary memory
|
|
2676
|
-
operations,</li>
|
|
2677
|
-
<li><strong>instcombine</strong> — merges simple operations,</li>
|
|
2678
|
-
<li><strong>gvn</strong> — removes redundant calculations,</li>
|
|
2679
|
-
<li><strong>simplifycfg</strong> — cleans up control flow.</li>
|
|
2680
|
-
</ul>
|
|
2681
|
-
<p>The compiler can run these passes automatically to produce compact
|
|
2682
|
-
and efficient output. LLVM also verifies that all types and values are
|
|
2683
|
-
consistent before emitting machine code.</p>
|
|
2684
|
-
<hr />
|
|
2685
|
-
<h2 id="summary-9"><strong>11.11 Summary</strong></h2>
|
|
2686
|
-
<ul>
|
|
2687
|
-
<li>LLVM IR is a portable, low-level language ideal for code
|
|
2688
|
-
generation.</li>
|
|
2689
|
-
<li>Every <code>k</code> function becomes an LLVM function returning the
|
|
2690
|
-
pair <code>{ok, value}</code>.</li>
|
|
2691
|
-
<li>All constants, type checks, and runtime calls are represented
|
|
2692
|
-
explicitly.</li>
|
|
2693
|
-
<li>The translation from <code>k</code>’s intermediate form to LLVM is
|
|
2694
|
-
direct and systematic.</li>
|
|
2695
|
-
<li>Standard LLVM tools can then optimize and compile the result into
|
|
2696
|
-
executable machine code.</li>
|
|
2697
|
-
</ul>
|
|
2698
|
-
<hr />
|
|
2699
|
-
<hr />
|
|
2700
|
-
<h1 id="chapter-12-code-generation">Chapter 12 — Code Generation</h1>
|
|
2701
|
-
<h2 id="purpose-3"><strong>12.1 Purpose</strong></h2>
|
|
2702
|
-
<p>The <strong>code generation</strong> phase translates the
|
|
2703
|
-
intermediate representation (IR) of each k function into executable code
|
|
2704
|
-
using the LLVM format described in Chapter 11. This translation is
|
|
2705
|
-
systematic: every IR operation corresponds to a specific sequence of
|
|
2706
|
-
LLVM instructions or calls to the runtime library.</p>
|
|
2707
|
-
<p>The compiler’s objective is to produce code that behaves exactly like
|
|
2708
|
-
the formal semantics of k—no more and no less. Each step of the
|
|
2709
|
-
translation can therefore be viewed as a mechanical implementation of
|
|
2710
|
-
one of the rules introduced in Chapter 8.</p>
|
|
2711
|
-
<hr />
|
|
2712
|
-
<h2 id="structure-of-generated-functions"><strong>12.2 Structure of
|
|
2713
|
-
generated functions</strong></h2>
|
|
2714
|
-
<p>Each k function becomes a stand-alone LLVM function with the
|
|
2715
|
-
signature:</p>
|
|
2716
|
-
<div class="sourceCode" id="cb97"><pre
|
|
2717
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb97-1"><a href="#cb97-1" aria-hidden="true" tabindex="-1"></a><span class="kw">define</span> <span class="fu">%KOpt</span> <span class="fu">@f_name</span>(<span class="fu">%KVal</span> <span class="fu">%in</span>)</span></code></pre></div>
|
|
2718
|
-
<p>Internally, the function has one or more <em>basic blocks</em>. Each
|
|
2719
|
-
block performs a small action: a projection, a check, a call, or a node
|
|
2720
|
-
construction. Blocks are connected by explicit branches that depend on
|
|
2721
|
-
the <code>ok</code> flag of intermediate results.</p>
|
|
2722
|
-
<p>At the end of the function, exactly one <code>%KOpt</code> value is
|
|
2723
|
-
returned.</p>
|
|
2724
|
-
<hr />
|
|
2725
|
-
<h2 id="translating-core-operations"><strong>12.3 Translating core
|
|
2726
|
-
operations</strong></h2>
|
|
2727
|
-
<p>The compiler maintains a mapping from IR operations (Chapter 10) to
|
|
2728
|
-
LLVM code patterns.</p>
|
|
2729
|
-
<table>
|
|
2730
|
-
<colgroup>
|
|
2731
|
-
<col style="width: 21%" />
|
|
2732
|
-
<col style="width: 78%" />
|
|
2733
|
-
</colgroup>
|
|
2734
|
-
<thead>
|
|
2735
|
-
<tr>
|
|
2736
|
-
<th>IR Operation</th>
|
|
2737
|
-
<th>Generated Code Pattern</th>
|
|
2738
|
-
</tr>
|
|
2739
|
-
</thead>
|
|
2740
|
-
<tbody>
|
|
2741
|
-
<tr>
|
|
2742
|
-
<td><strong>PROJECT label</strong></td>
|
|
2743
|
-
<td><code>call %KOpt @k_project(%KVal %in, i32 label_id)</code></td>
|
|
2744
|
-
</tr>
|
|
2745
|
-
<tr>
|
|
2746
|
-
<td><strong>TYPECHECK state</strong></td>
|
|
2747
|
-
<td>Compare <code>input->state</code> with constant
|
|
2748
|
-
<code>state</code>; if unequal, return <code>{0, undef}</code></td>
|
|
2749
|
-
</tr>
|
|
2750
|
-
<tr>
|
|
2751
|
-
<td><strong>CONST node</strong></td>
|
|
2752
|
-
<td>Return <code>{1, node_pointer}</code></td>
|
|
2753
|
-
</tr>
|
|
2754
|
-
<tr>
|
|
2755
|
-
<td><strong>SEQ [f₁,f₂,…]</strong></td>
|
|
2756
|
-
<td>Emit each function call in order, test <code>ok</code> after
|
|
2757
|
-
each</td>
|
|
2758
|
-
</tr>
|
|
2759
|
-
<tr>
|
|
2760
|
-
<td><strong>UNION [f₁,f₂,…]</strong></td>
|
|
2761
|
-
<td>Emit chained <code>if</code> blocks; return first successful
|
|
2762
|
-
result</td>
|
|
2763
|
-
</tr>
|
|
2764
|
-
<tr>
|
|
2765
|
-
<td><strong>PRODUCT [l₁=f₁, …]</strong></td>
|
|
2766
|
-
<td>Call all subfunctions; if all succeed, collect children and call
|
|
2767
|
-
<code>@k_make_product</code></td>
|
|
2768
|
-
</tr>
|
|
2769
|
-
<tr>
|
|
2770
|
-
<td><strong>FAIL</strong></td>
|
|
2771
|
-
<td>Return <code>{0, undef}</code> immediately</td>
|
|
2772
|
-
</tr>
|
|
2773
|
-
</tbody>
|
|
2774
|
-
</table>
|
|
2775
|
-
<p>These templates cover the entire language.</p>
|
|
2776
|
-
<hr />
|
|
2777
|
-
<h2 id="example-sequential-composition"><strong>12.4 Example: sequential
|
|
2778
|
-
composition</strong></h2>
|
|
2779
|
-
<p>For IR:</p>
|
|
2780
|
-
<pre><code>SEQ [ PROJECT x, CALL f, CALL g ]</code></pre>
|
|
2781
|
-
<p>the compiler emits:</p>
|
|
2782
|
-
<div class="sourceCode" id="cb99"><pre
|
|
2783
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb99-1"><a href="#cb99-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
|
|
2784
|
-
<span id="cb99-2"><a href="#cb99-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
|
|
2785
|
-
<span id="cb99-3"><a href="#cb99-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%cont1</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
|
|
2786
|
-
<span id="cb99-4"><a href="#cb99-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
2787
|
-
<span id="cb99-5"><a href="#cb99-5" aria-hidden="true" tabindex="-1"></a><span class="fu">cont1:</span></span>
|
|
2788
|
-
<span id="cb99-6"><a href="#cb99-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@f</span>(<span class="fu">%r1.val</span>)</span>
|
|
2789
|
-
<span id="cb99-7"><a href="#cb99-7" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok2</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r2</span>, <span class="dv">0</span></span>
|
|
2790
|
-
<span id="cb99-8"><a href="#cb99-8" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok2</span>, <span class="dt">label</span> <span class="fu">%cont2</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
|
|
2791
|
-
<span id="cb99-9"><a href="#cb99-9" aria-hidden="true" tabindex="-1"></a></span>
|
|
2792
|
-
<span id="cb99-10"><a href="#cb99-10" aria-hidden="true" tabindex="-1"></a><span class="fu">cont2:</span></span>
|
|
2793
|
-
<span id="cb99-11"><a href="#cb99-11" aria-hidden="true" tabindex="-1"></a><span class="fu">%r3</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@g</span>(<span class="fu">%r2.val</span>)</span>
|
|
2794
|
-
<span id="cb99-12"><a href="#cb99-12" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%r3</span></span>
|
|
2795
|
-
<span id="cb99-13"><a href="#cb99-13" aria-hidden="true" tabindex="-1"></a></span>
|
|
2796
|
-
<span id="cb99-14"><a href="#cb99-14" aria-hidden="true" tabindex="-1"></a><span class="fu">fail:</span></span>
|
|
2797
|
-
<span id="cb99-15"><a href="#cb99-15" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span></code></pre></div>
|
|
2798
|
-
<p>Each block corresponds to one stage in the composition. The use of
|
|
2799
|
-
conditional branches ensures that undefinedness propagates
|
|
2800
|
-
correctly.</p>
|
|
2801
|
-
<hr />
|
|
2802
|
-
<h2 id="example-product-composition-1"><strong>12.5 Example: product
|
|
2803
|
-
composition</strong></h2>
|
|
2804
|
-
<p>For IR:</p>
|
|
2805
|
-
<pre><code>PRODUCT [ a = PROJECT x, b = PROJECT y ]</code></pre>
|
|
2806
|
-
<p>the compiler generates code equivalent to:</p>
|
|
2807
|
-
<div class="sourceCode" id="cb101"><pre
|
|
2808
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb101-1"><a href="#cb101-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%ra</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
|
|
2809
|
-
<span id="cb101-2"><a href="#cb101-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_a</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%ra</span>, <span class="dv">0</span></span>
|
|
2810
|
-
<span id="cb101-3"><a href="#cb101-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok_a</span>, <span class="dt">label</span> <span class="fu">%try_b</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
|
|
2811
|
-
<span id="cb101-4"><a href="#cb101-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
2812
|
-
<span id="cb101-5"><a href="#cb101-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_b:</span></span>
|
|
2813
|
-
<span id="cb101-6"><a href="#cb101-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%rb</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_y</span>(<span class="fu">%in</span>)</span>
|
|
2814
|
-
<span id="cb101-7"><a href="#cb101-7" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_b</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%rb</span>, <span class="dv">0</span></span>
|
|
2815
|
-
<span id="cb101-8"><a href="#cb101-8" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok_all</span> = <span class="kw">and</span> <span class="dt">i1</span> <span class="fu">%ok_a</span>, <span class="fu">%ok_b</span></span>
|
|
2816
|
-
<span id="cb101-9"><a href="#cb101-9" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok_all</span>, <span class="dt">label</span> <span class="fu">%build</span>, <span class="dt">label</span> <span class="fu">%fail</span></span>
|
|
2817
|
-
<span id="cb101-10"><a href="#cb101-10" aria-hidden="true" tabindex="-1"></a></span>
|
|
2818
|
-
<span id="cb101-11"><a href="#cb101-11" aria-hidden="true" tabindex="-1"></a><span class="fu">build:</span></span>
|
|
2819
|
-
<span id="cb101-12"><a href="#cb101-12" aria-hidden="true" tabindex="-1"></a><span class="fu">%children</span> = <span class="kw">alloca</span> [<span class="fu">%KVal</span>, <span class="dv">2</span>]</span>
|
|
2820
|
-
<span id="cb101-13"><a href="#cb101-13" aria-hidden="true" tabindex="-1"></a><span class="fu">%p0</span> = <span class="kw">getelementptr</span> [<span class="fu">%KVal</span>,<span class="dv">2</span>], [<span class="fu">%KVal</span>,<span class="dv">2</span>]* <span class="fu">%children</span>, <span class="dt">i32</span> <span class="dv">0</span>, <span class="dt">i32</span> <span class="dv">0</span></span>
|
|
2821
|
-
<span id="cb101-14"><a href="#cb101-14" aria-hidden="true" tabindex="-1"></a><span class="kw">store</span> <span class="fu">%KVal</span> (<span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%ra</span>, <span class="dv">1</span>), <span class="fu">%KVal</span>* <span class="fu">%p0</span></span>
|
|
2822
|
-
<span id="cb101-15"><a href="#cb101-15" aria-hidden="true" tabindex="-1"></a><span class="fu">%p1</span> = <span class="kw">getelementptr</span> [<span class="fu">%KVal</span>,<span class="dv">2</span>], [<span class="fu">%KVal</span>,<span class="dv">2</span>]* <span class="fu">%children</span>, <span class="dt">i32</span> <span class="dv">0</span>, <span class="dt">i32</span> <span class="dv">1</span></span>
|
|
2823
|
-
<span id="cb101-16"><a href="#cb101-16" aria-hidden="true" tabindex="-1"></a><span class="kw">store</span> <span class="fu">%KVal</span> (<span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%rb</span>, <span class="dv">1</span>), <span class="fu">%KVal</span>* <span class="fu">%p1</span></span>
|
|
2824
|
-
<span id="cb101-17"><a href="#cb101-17" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">call</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> state_id, <span class="dt">i32</span> <span class="dv">2</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
|
|
2825
|
-
<span id="cb101-18"><a href="#cb101-18" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">1</span>, <span class="fu">%KVal</span> <span class="fu">%res</span> }</span>
|
|
2826
|
-
<span id="cb101-19"><a href="#cb101-19" aria-hidden="true" tabindex="-1"></a></span>
|
|
2827
|
-
<span id="cb101-20"><a href="#cb101-20" aria-hidden="true" tabindex="-1"></a><span class="fu">fail:</span></span>
|
|
2828
|
-
<span id="cb101-21"><a href="#cb101-21" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> { <span class="dt">i1</span> <span class="dv">0</span>, <span class="fu">%KVal</span> <span class="kw">undef</span> }</span></code></pre></div>
|
|
2829
|
-
<p>The resulting LLVM code faithfully follows the semantic rule: the
|
|
2830
|
-
product is defined only if all components are defined.</p>
|
|
2831
|
-
<hr />
|
|
2832
|
-
<h2 id="example-union-composition"><strong>12.6 Example: union
|
|
2833
|
-
composition</strong></h2>
|
|
2834
|
-
<p>For IR:</p>
|
|
2835
|
-
<pre><code>UNION [ .x, .y ]</code></pre>
|
|
2836
|
-
<p>the compiler produces a branching structure:</p>
|
|
2837
|
-
<div class="sourceCode" id="cb103"><pre
|
|
2838
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb103-1"><a href="#cb103-1" aria-hidden="true" tabindex="-1"></a><span class="fu">%r1</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_x</span>(<span class="fu">%in</span>)</span>
|
|
2839
|
-
<span id="cb103-2"><a href="#cb103-2" aria-hidden="true" tabindex="-1"></a><span class="fu">%ok1</span> = <span class="kw">extractvalue</span> <span class="fu">%KOpt</span> <span class="fu">%r1</span>, <span class="dv">0</span></span>
|
|
2840
|
-
<span id="cb103-3"><a href="#cb103-3" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">i1</span> <span class="fu">%ok1</span>, <span class="dt">label</span> <span class="fu">%merge</span>, <span class="dt">label</span> <span class="fu">%try_next</span></span>
|
|
2841
|
-
<span id="cb103-4"><a href="#cb103-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
2842
|
-
<span id="cb103-5"><a href="#cb103-5" aria-hidden="true" tabindex="-1"></a><span class="fu">try_next:</span></span>
|
|
2843
|
-
<span id="cb103-6"><a href="#cb103-6" aria-hidden="true" tabindex="-1"></a><span class="fu">%r2</span> = <span class="kw">call</span> <span class="fu">%KOpt</span> <span class="fu">@k_project_y</span>(<span class="fu">%in</span>)</span>
|
|
2844
|
-
<span id="cb103-7"><a href="#cb103-7" aria-hidden="true" tabindex="-1"></a><span class="kw">br</span> <span class="dt">label</span> <span class="fu">%merge</span></span>
|
|
2845
|
-
<span id="cb103-8"><a href="#cb103-8" aria-hidden="true" tabindex="-1"></a></span>
|
|
2846
|
-
<span id="cb103-9"><a href="#cb103-9" aria-hidden="true" tabindex="-1"></a><span class="fu">merge:</span></span>
|
|
2847
|
-
<span id="cb103-10"><a href="#cb103-10" aria-hidden="true" tabindex="-1"></a><span class="fu">%res</span> = <span class="kw">phi</span> <span class="fu">%KOpt</span> [ <span class="fu">%r1</span>, <span class="fu">%ok1</span> ], [ <span class="fu">%r2</span>, <span class="fu">%try_next</span> ]</span>
|
|
2848
|
-
<span id="cb103-11"><a href="#cb103-11" aria-hidden="true" tabindex="-1"></a><span class="kw">ret</span> <span class="fu">%KOpt</span> <span class="fu">%res</span></span></code></pre></div>
|
|
2849
|
-
<p>This pattern ensures that the first defined branch wins, as specified
|
|
2850
|
-
by the semantics.</p>
|
|
2851
|
-
<hr />
|
|
2852
|
-
<h2 id="managing-constants-and-types"><strong>12.7 Managing constants
|
|
2853
|
-
and types</strong></h2>
|
|
2854
|
-
<p>Whenever an expression references a constant value or a type
|
|
2855
|
-
restriction:</p>
|
|
2856
|
-
<ul>
|
|
2857
|
-
<li><strong>Constant values</strong> are replaced by pointers to global
|
|
2858
|
-
constant nodes.</li>
|
|
2859
|
-
<li><strong>Type expressions <code>$T</code></strong> are compiled to a
|
|
2860
|
-
<code>TYPECHECK</code> instruction: if
|
|
2861
|
-
<code>input->state != T_state</code>, the function returns
|
|
2862
|
-
undefined.</li>
|
|
2863
|
-
</ul>
|
|
2864
|
-
<p>This approach removes all high-level notation before reaching machine
|
|
2865
|
-
level.</p>
|
|
2866
|
-
<hr />
|
|
2867
|
-
<h2 id="optimizing-during-generation"><strong>12.8 Optimizing during
|
|
2868
|
-
generation</strong></h2>
|
|
2869
|
-
<p>Because the structure of k is very regular, many optimizations can be
|
|
2870
|
-
applied while generating code:</p>
|
|
2871
|
-
<ul>
|
|
2872
|
-
<li><strong>Eliminate redundant checks</strong> — consecutive type
|
|
2873
|
-
checks on the same state can be merged.</li>
|
|
2874
|
-
<li><strong>Inline small functions</strong> — short constant or
|
|
2875
|
-
projection functions can be inserted directly into their callers.</li>
|
|
2876
|
-
<li><strong>Remove unreachable branches</strong> — if a type restriction
|
|
2877
|
-
guarantees that one union branch can never apply, it is omitted.</li>
|
|
2878
|
-
</ul>
|
|
2879
|
-
<p>Such simplifications can be done by the compiler itself or delegated
|
|
2880
|
-
to LLVM’s optimization passes.</p>
|
|
2881
|
-
<hr />
|
|
2882
|
-
<h2 id="interaction-with-the-runtime"><strong>12.9 Interaction with the
|
|
2883
|
-
runtime</strong></h2>
|
|
2884
|
-
<p>All allocation and field access are performed through runtime calls.
|
|
2885
|
-
The compiler never manipulates pointers directly beyond passing them to
|
|
2886
|
-
these helpers. This design ensures that compiled code is independent of
|
|
2887
|
-
the internal memory layout.</p>
|
|
2888
|
-
<p>The generated functions thus resemble small graphs of calls and
|
|
2889
|
-
conditionals built entirely on top of the fixed ABI.</p>
|
|
2890
|
-
<hr />
|
|
2891
|
-
<h2 id="linking-and-verification"><strong>12.10 Linking and
|
|
2892
|
-
verification</strong></h2>
|
|
2893
|
-
<p>After all functions are emitted, the compiler writes a single LLVM
|
|
2894
|
-
module containing:</p>
|
|
2895
|
-
<ul>
|
|
2896
|
-
<li>all generated functions,</li>
|
|
2897
|
-
<li>declarations of runtime primitives (<code>k_project</code>,
|
|
2898
|
-
<code>k_make_product</code>, etc.),</li>
|
|
2899
|
-
<li>and constant nodes representing literal values.</li>
|
|
2900
|
-
</ul>
|
|
2901
|
-
<p>The LLVM verifier then checks that:</p>
|
|
2902
|
-
<ul>
|
|
2903
|
-
<li>every function returns a correctly typed <code>%KOpt</code>,</li>
|
|
2904
|
-
<li>all control-flow paths end with a <code>ret</code>,</li>
|
|
2905
|
-
<li>and all global references are defined.</li>
|
|
2906
|
-
</ul>
|
|
2907
|
-
<p>Only verified code is passed to the optimizer or the machine-code
|
|
2908
|
-
generator.</p>
|
|
2909
|
-
<hr />
|
|
2910
|
-
<h2 id="summary-10"><strong>12.11 Summary</strong></h2>
|
|
2911
|
-
<ul>
|
|
2912
|
-
<li>Code generation turns IR into real executable instructions.</li>
|
|
2913
|
-
<li>Each k function maps to an LLVM function returning
|
|
2914
|
-
<code>{ok, value}</code>.</li>
|
|
2915
|
-
<li>Projection, composition, union, and product translate into small,
|
|
2916
|
-
fixed code patterns.</li>
|
|
2917
|
-
<li>Type restrictions become simple integer comparisons.</li>
|
|
2918
|
-
<li>The compiler can apply immediate simplifications during
|
|
2919
|
-
translation.</li>
|
|
2920
|
-
<li>The final output is a verified LLVM module ready for optimization
|
|
2921
|
-
and linking.</li>
|
|
2922
|
-
</ul>
|
|
2923
|
-
<h1 id="chapter-13-linking-and-execution">Chapter 13 — Linking and
|
|
2924
|
-
Execution</h1>
|
|
2925
|
-
<h2 id="purpose-4"><strong>13.1 Purpose</strong></h2>
|
|
2926
|
-
<p>The last stage of compilation connects the generated code with the
|
|
2927
|
-
runtime library and produces an executable program. This process is
|
|
2928
|
-
called <strong>linking</strong>. Once linked, the program can be run
|
|
2929
|
-
like any other compiled program: it reads input values, executes the
|
|
2930
|
-
compiled k functions, and returns a result.</p>
|
|
2931
|
-
<p>The linking and execution stages ensure that the compiled code, the
|
|
2932
|
-
runtime library, and the data it manipulates all agree on structure and
|
|
2933
|
-
conventions.</p>
|
|
2934
|
-
<hr />
|
|
2935
|
-
<h2 id="the-runtime-library"><strong>13.2 The runtime
|
|
2936
|
-
library</strong></h2>
|
|
2937
|
-
<p>All compiled k programs depend on a small runtime component, often
|
|
2938
|
-
distributed as a file named <code>krt.c</code> or <code>krt.o</code>.
|
|
2939
|
-
This library provides:</p>
|
|
2940
|
-
<table>
|
|
2941
|
-
<colgroup>
|
|
2942
|
-
<col style="width: 41%" />
|
|
2943
|
-
<col style="width: 58%" />
|
|
2944
|
-
</colgroup>
|
|
2945
|
-
<thead>
|
|
2946
|
-
<tr>
|
|
2947
|
-
<th>Function</th>
|
|
2948
|
-
<th>Purpose</th>
|
|
2949
|
-
</tr>
|
|
2950
|
-
</thead>
|
|
2951
|
-
<tbody>
|
|
2952
|
-
<tr>
|
|
2953
|
-
<td><code>k_make_product(state, n, children)</code></td>
|
|
2954
|
-
<td>Allocate a product node with <code>n</code> fields.</td>
|
|
2955
|
-
</tr>
|
|
2956
|
-
<tr>
|
|
2957
|
-
<td><code>k_make_union(state, tag, child)</code></td>
|
|
2958
|
-
<td>Allocate a union node with a single variant.</td>
|
|
2959
|
-
</tr>
|
|
2960
|
-
<tr>
|
|
2961
|
-
<td><code>k_project(input, label_id)</code></td>
|
|
2962
|
-
<td>Perform projection <code>.label</code>.</td>
|
|
2963
|
-
</tr>
|
|
2964
|
-
<tr>
|
|
2965
|
-
<td><code>k_fail()</code></td>
|
|
2966
|
-
<td>Return a predefined undefined result <code>{ ok = 0 }</code>.</td>
|
|
2967
|
-
</tr>
|
|
2968
|
-
<tr>
|
|
2969
|
-
<td><code>k_unit()</code></td>
|
|
2970
|
-
<td>Return the constant unit value <code>{}</code>.</td>
|
|
2971
|
-
</tr>
|
|
2972
|
-
</tbody>
|
|
2973
|
-
</table>
|
|
2974
|
-
<p>These functions implement the same concepts as the semantic rules
|
|
2975
|
-
described earlier, but at the level of actual memory operations. They
|
|
2976
|
-
are compiled once in a low-level language such as C and reused by all
|
|
2977
|
-
generated programs.</p>
|
|
2978
|
-
<hr />
|
|
2979
|
-
<h2 id="metadata-tables-1"><strong>13.3 Metadata tables</strong></h2>
|
|
2980
|
-
<p>Along with the runtime functions, the compiler produces
|
|
2981
|
-
<strong>metadata</strong> describing each canonical type used in the
|
|
2982
|
-
program:</p>
|
|
2983
|
-
<ul>
|
|
2984
|
-
<li><code>state_kind[state]</code> — <code>0</code> for product,
|
|
2985
|
-
<code>1</code> for union</li>
|
|
2986
|
-
<li><code>state_arity[state]</code> — number of children</li>
|
|
2987
|
-
<li><code>field_index[state][label_id]</code> — position of field
|
|
2988
|
-
<code>label_id</code> within product</li>
|
|
2989
|
-
<li><code>variant_index[state][label_id]</code> — tag number for variant
|
|
2990
|
-
<code>label_id</code> within union</li>
|
|
2991
|
-
</ul>
|
|
2992
|
-
<p>These tables are stored as constant arrays in the compiled module.
|
|
2993
|
-
Runtime functions use them to interpret and construct nodes correctly
|
|
2994
|
-
without needing any dynamic reflection.</p>
|
|
2995
|
-
<hr />
|
|
2996
|
-
<h2 id="linking"><strong>13.4 Linking</strong></h2>
|
|
2997
|
-
<p>The generated LLVM file is compiled and linked with the runtime
|
|
2998
|
-
library in two simple steps:</p>
|
|
2999
|
-
<div class="sourceCode" id="cb104"><pre
|
|
3000
|
-
class="sourceCode bash"><code class="sourceCode bash"><span id="cb104-1"><a href="#cb104-1" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> <span class="at">-c</span> krt.c <span class="at">-o</span> krt.o</span>
|
|
3001
|
-
<span id="cb104-2"><a href="#cb104-2" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> program.ll krt.o <span class="at">-o</span> program</span></code></pre></div>
|
|
3002
|
-
<p>The first command compiles the runtime once. The second command
|
|
3003
|
-
combines the runtime with the program’s own functions and constant
|
|
3004
|
-
definitions.</p>
|
|
3005
|
-
<p>The result is a native executable file named <code>program</code>.
|
|
3006
|
-
When run, it behaves exactly like the original k program.</p>
|
|
3007
|
-
<hr />
|
|
3008
|
-
<h2 id="initialization"><strong>13.5 Initialization</strong></h2>
|
|
3009
|
-
<p>When the executable starts, it performs a few basic steps:</p>
|
|
3010
|
-
<ol type="1">
|
|
3011
|
-
<li>Allocate an <strong>arena</strong> for storing newly created
|
|
3012
|
-
nodes.</li>
|
|
3013
|
-
<li>Initialize constant nodes such as the unit <code>{}</code> and any
|
|
3014
|
-
user-defined constants.</li>
|
|
3015
|
-
<li>Optionally, prepare a table of function pointers for fast
|
|
3016
|
-
invocation.</li>
|
|
3017
|
-
</ol>
|
|
3018
|
-
<p>After initialization, the main compiled function can be called
|
|
3019
|
-
directly.</p>
|
|
3020
|
-
<hr />
|
|
3021
|
-
<h2 id="executing-a-compiled-function"><strong>13.6 Executing a compiled
|
|
3022
|
-
function</strong></h2>
|
|
3023
|
-
<p>Every compiled function has the signature:</p>
|
|
3024
|
-
<div class="sourceCode" id="cb105"><pre
|
|
3025
|
-
class="sourceCode c"><code class="sourceCode c"><span id="cb105-1"><a href="#cb105-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt function<span class="op">(</span><span class="kw">struct</span> KNode<span class="op">*</span> input<span class="op">);</span></span></code></pre></div>
|
|
3026
|
-
<p>To run a program, a caller must supply an input value tree in the
|
|
3027
|
-
expected canonical form. The value is typically created by another
|
|
3028
|
-
function or loaded from serialized data.</p>
|
|
3029
|
-
<p>For example, to execute a function <code>neg</code> expecting a
|
|
3030
|
-
<code>$bool</code>:</p>
|
|
3031
|
-
<div class="sourceCode" id="cb106"><pre
|
|
3032
|
-
class="sourceCode c"><code class="sourceCode c"><span id="cb106-1"><a href="#cb106-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> KOpt result <span class="op">=</span> neg<span class="op">(&</span>true_node<span class="op">);</span></span>
|
|
3033
|
-
<span id="cb106-2"><a href="#cb106-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>result<span class="op">.</span>ok<span class="op">)</span></span>
|
|
3034
|
-
<span id="cb106-3"><a href="#cb106-3" aria-hidden="true" tabindex="-1"></a> print_value<span class="op">(</span>result<span class="op">.</span>val<span class="op">);</span></span>
|
|
3035
|
-
<span id="cb106-4"><a href="#cb106-4" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span></span>
|
|
3036
|
-
<span id="cb106-5"><a href="#cb106-5" aria-hidden="true" tabindex="-1"></a> printf<span class="op">(</span><span class="st">"undefined</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span></code></pre></div>
|
|
3037
|
-
<p>If the input is <code>{ {} true }</code>, the output will be
|
|
3038
|
-
<code>{ {} false }</code>.</p>
|
|
3039
|
-
<hr />
|
|
3040
|
-
<h2 id="input-and-output-conventions"><strong>13.7 Input and output
|
|
3041
|
-
conventions</strong></h2>
|
|
3042
|
-
<p>At the machine level, a “value” is always represented by a pointer to
|
|
3043
|
-
a <code>KNode</code>. Each compiled function expects exactly one such
|
|
3044
|
-
pointer. When a function returns, its output pointer may refer to an
|
|
3045
|
-
existing constant node, a new node allocated in the arena, or nothing at
|
|
3046
|
-
all if undefined.</p>
|
|
3047
|
-
<p>There is no special I/O system in k itself; printing or reading
|
|
3048
|
-
values is the responsibility of the host environment. In practice,
|
|
3049
|
-
programs are tested by calling compiled functions from C or Python and
|
|
3050
|
-
inspecting their returned structures.</p>
|
|
3051
|
-
<hr />
|
|
3052
|
-
<h2 id="debugging-and-inspection"><strong>13.8 Debugging and
|
|
3053
|
-
inspection</strong></h2>
|
|
3054
|
-
<p>Because both the generated code and the runtime library are
|
|
3055
|
-
deterministic and memory-safe, debugging usually consists of examining
|
|
3056
|
-
node contents.</p>
|
|
3057
|
-
<p>Two simple runtime utilities are useful:</p>
|
|
3058
|
-
<ul>
|
|
3059
|
-
<li><code>print_value(node)</code> — prints a tree in human-readable
|
|
3060
|
-
form.</li>
|
|
3061
|
-
<li><code>print_type(state)</code> — prints the canonical description of
|
|
3062
|
-
a type state.</li>
|
|
3063
|
-
</ul>
|
|
3064
|
-
<p>They allow the user to confirm that compiled functions construct the
|
|
3065
|
-
correct tree shapes.</p>
|
|
3066
|
-
<hr />
|
|
3067
|
-
<h2 id="verification"><strong>13.9 Verification</strong></h2>
|
|
3068
|
-
<p>After linking, the compiler can run a <em>self-verification
|
|
3069
|
-
pass</em>:</p>
|
|
3070
|
-
<ol type="1">
|
|
3071
|
-
<li>Construct small sample inputs for each exported function.</li>
|
|
3072
|
-
<li>Execute the compiled function.</li>
|
|
3073
|
-
<li>Compare results with the interpreter’s result using structural
|
|
3074
|
-
equality.</li>
|
|
3075
|
-
</ol>
|
|
3076
|
-
<p>If all match, the compiler’s translation is confirmed correct for
|
|
3077
|
-
those test cases. This method is especially valuable during compiler
|
|
3078
|
-
development and textbook exercises.</p>
|
|
3079
|
-
<hr />
|
|
3080
|
-
<h2 id="example-complete-run"><strong>13.10 Example: complete
|
|
3081
|
-
run</strong></h2>
|
|
3082
|
-
<p>Example program:</p>
|
|
3083
|
-
<pre><code>$bool = < {} true, {} false >;
|
|
3084
|
-
neg = $bool < .true {{ } false}, .false {{ } true} > $bool;</code></pre>
|
|
3085
|
-
<p>Steps:</p>
|
|
3086
|
-
<ol type="1">
|
|
3087
|
-
<li>Compile to <code>neg.ll</code>.</li>
|
|
3088
|
-
<li>Link with <code>krt.o</code>.</li>
|
|
3089
|
-
<li>Run a small C driver that calls <code>neg</code>.</li>
|
|
3090
|
-
</ol>
|
|
3091
|
-
<p>Output:</p>
|
|
3092
|
-
<pre><code>input = {{ } true}
|
|
3093
|
-
result = {{ } false}</code></pre>
|
|
3094
|
-
<p>If <code>input</code> is <code>{}</code> or any
|
|
3095
|
-
non-<code>$bool</code> value, the function is undefined and prints
|
|
3096
|
-
“undefined”.</p>
|
|
3097
|
-
<hr />
|
|
3098
|
-
<h2 id="summary-11"><strong>13.11 Summary</strong></h2>
|
|
3099
|
-
<ul>
|
|
3100
|
-
<li>Linking combines generated LLVM code with the shared runtime
|
|
3101
|
-
library.</li>
|
|
3102
|
-
<li>The runtime provides allocation, projection, and constant
|
|
3103
|
-
handling.</li>
|
|
3104
|
-
<li>Metadata tables describe type structure to the runtime.</li>
|
|
3105
|
-
<li>Every compiled function follows the uniform calling convention
|
|
3106
|
-
<code>KOpt f(KNode*)</code>.</li>
|
|
3107
|
-
<li>Execution produces immutable tree values exactly matching the
|
|
3108
|
-
semantics of k.</li>
|
|
3109
|
-
<li>Verification against the interpreter ensures correctness of the
|
|
3110
|
-
translation.</li>
|
|
3111
|
-
</ul>
|
|
3112
|
-
<h1 id="chapter-14-canonical-serialization">Chapter 14 — Canonical
|
|
3113
|
-
Serialization</h1>
|
|
3114
|
-
<h2 id="purpose-5"><strong>14.1 Purpose</strong></h2>
|
|
3115
|
-
<p>Serialization is the process of converting a value in memory into a
|
|
3116
|
-
compact sequence of bits or bytes that can be stored or transmitted. For
|
|
3117
|
-
the k language, serialization serves an additional goal: it defines a
|
|
3118
|
-
<strong>canonical representation</strong> of each value that is unique
|
|
3119
|
-
and independent of the machine on which it was produced.</p>
|
|
3120
|
-
<p>A canonical encoding allows values to be compared, hashed, or stored
|
|
3121
|
-
in a registry in a reproducible way. Two values that are structurally
|
|
3122
|
-
identical will always produce the same bit sequence.</p>
|
|
3123
|
-
<hr />
|
|
3124
|
-
<h2 id="canonical-type-information"><strong>14.2 Canonical type
|
|
3125
|
-
information</strong></h2>
|
|
3126
|
-
<p>Serialization always depends on the <strong>canonical form of the
|
|
3127
|
-
type</strong>. A type in canonical form is a finite tree automaton
|
|
3128
|
-
(Chapter 3) that describes the structure of all its values. Because this
|
|
3129
|
-
form is unique, every possible value of the type can be encoded
|
|
3130
|
-
deterministically.</p>
|
|
3131
|
-
<p>Before any value is serialized, the compiler or runtime must
|
|
3132
|
-
know:</p>
|
|
3133
|
-
<ul>
|
|
3134
|
-
<li>the list of states (C0, C1, …),</li>
|
|
3135
|
-
<li>for each state, whether it is a product or a union,</li>
|
|
3136
|
-
<li>the number of possible transitions, and</li>
|
|
3137
|
-
<li>for unions, the order of their variants.</li>
|
|
3138
|
-
</ul>
|
|
3139
|
-
<p>This information acts as the grammar from which all bit sequences are
|
|
3140
|
-
derived.</p>
|
|
3141
|
-
<hr />
|
|
3142
|
-
<h2 id="encoding-principle"><strong>14.3 Encoding
|
|
3143
|
-
principle</strong></h2>
|
|
3144
|
-
<p>Each node in a value tree corresponds to one of the type’s
|
|
3145
|
-
states.</p>
|
|
3146
|
-
<ul>
|
|
3147
|
-
<li><strong>Product node</strong> – emits no bits; the encoder simply
|
|
3148
|
-
serializes each child in canonical field order.</li>
|
|
3149
|
-
<li><strong>Union node</strong> – emits a small binary code that
|
|
3150
|
-
identifies which variant is used, then serializes its single child.</li>
|
|
3151
|
-
<li><strong>Unit node</strong> (empty product) – emits nothing; it has
|
|
3152
|
-
no children.</li>
|
|
3153
|
-
<li><strong>Empty union</strong> – cannot be encoded because it has no
|
|
3154
|
-
possible values.</li>
|
|
3155
|
-
</ul>
|
|
3156
|
-
<p>Thus, the sequence of bits records exactly which union branches were
|
|
3157
|
-
taken while descending the tree.</p>
|
|
3158
|
-
<hr />
|
|
3159
|
-
<h2 id="fixed-length-codes-per-state"><strong>14.4 Fixed-length codes
|
|
3160
|
-
per state</strong></h2>
|
|
3161
|
-
<p>For simplicity, each union state uses fixed-length binary codes of
|
|
3162
|
-
equal size.</p>
|
|
3163
|
-
<p>If a union has <em>m</em> variants, then</p>
|
|
3164
|
-
<pre><code>k = ceil(log2(m))</code></pre>
|
|
3165
|
-
<p>bits are needed. Each variant is numbered in canonical order from 0
|
|
3166
|
-
to m − 1 and represented by the binary form of its index.</p>
|
|
3167
|
-
<p>Products and units use k = 0 and emit no bits.</p>
|
|
3168
|
-
<p>This rule allows the decoder to know, from the type alone, how many
|
|
3169
|
-
bits to read at each step.</p>
|
|
3170
|
-
<hr />
|
|
3171
|
-
<h2 id="example-natural-numbers-1"><strong>14.5 Example: natural
|
|
3172
|
-
numbers</strong></h2>
|
|
3173
|
-
<p>For the type</p>
|
|
3174
|
-
<pre><code>$bnat = < bnat 0, bnat 1, {} _ >;</code></pre>
|
|
3175
|
-
<p>the canonical form has three transitions from state C0. Therefore,
|
|
3176
|
-
<code>k = ceil(log2(3)) = 2</code> bits are required per union node.</p>
|
|
3177
|
-
<p>Assigning codes in order:</p>
|
|
3178
|
-
<table>
|
|
3179
|
-
<thead>
|
|
3180
|
-
<tr>
|
|
3181
|
-
<th>Rule</th>
|
|
3182
|
-
<th>Code</th>
|
|
3183
|
-
</tr>
|
|
3184
|
-
</thead>
|
|
3185
|
-
<tbody>
|
|
3186
|
-
<tr>
|
|
3187
|
-
<td>C0 → {C0 “0”}</td>
|
|
3188
|
-
<td><code>00</code></td>
|
|
3189
|
-
</tr>
|
|
3190
|
-
<tr>
|
|
3191
|
-
<td>C0 → {C0 “1”}</td>
|
|
3192
|
-
<td><code>01</code></td>
|
|
3193
|
-
</tr>
|
|
3194
|
-
<tr>
|
|
3195
|
-
<td>C0 → {C1 “_” }</td>
|
|
3196
|
-
<td><code>10</code></td>
|
|
3197
|
-
</tr>
|
|
3198
|
-
</tbody>
|
|
3199
|
-
</table>
|
|
3200
|
-
<p>The value <code>{ {{ {} _ } 1 } 0 }</code> is encoded by
|
|
3201
|
-
concatenating the codes of the transitions chosen during a leftmost
|
|
3202
|
-
derivation:</p>
|
|
3203
|
-
<pre><code>00 → first C0
|
|
3204
|
-
01 → next C0
|
|
3205
|
-
10 → final C0</code></pre>
|
|
3206
|
-
<p>Resulting bit sequence: <code>000110</code>.</p>
|
|
3207
|
-
<hr />
|
|
3208
|
-
<h2 id="decoding"><strong>14.6 Decoding</strong></h2>
|
|
3209
|
-
<p>Decoding is deterministic and mirrors the encoding process:</p>
|
|
3210
|
-
<ol type="1">
|
|
3211
|
-
<li>Start at the root state (C0).</li>
|
|
3212
|
-
<li>If the current state is a union, read k bits to choose a rule.</li>
|
|
3213
|
-
<li>Create the corresponding node, then recursively decode its child or
|
|
3214
|
-
children.</li>
|
|
3215
|
-
<li>For products, decode all children in order; for units, stop.</li>
|
|
3216
|
-
</ol>
|
|
3217
|
-
<p>The decoder stops when the entire tree has been reconstructed and all
|
|
3218
|
-
bits have been consumed.</p>
|
|
3219
|
-
<p>Because every union code is of fixed length, the decoding process
|
|
3220
|
-
requires no backtracking and can be implemented as a simple loop.</p>
|
|
3221
|
-
<hr />
|
|
3222
|
-
<h2 id="folding-repeated-subtrees"><strong>14.7 Folding repeated
|
|
3223
|
-
subtrees</strong></h2>
|
|
3224
|
-
<p>Many values contain repeated substructures. To avoid serializing the
|
|
3225
|
-
same tree several times, identical subtrees can be <em>folded</em> into
|
|
3226
|
-
a <strong>directed acyclic graph (DAG)</strong> before encoding.</p>
|
|
3227
|
-
<p>Each unique node is assigned an identifier. When the encoder
|
|
3228
|
-
encounters a repeated node, it emits a reference to its identifier
|
|
3229
|
-
instead of encoding it again.</p>
|
|
3230
|
-
<p>During decoding, the identifier is resolved to the corresponding
|
|
3231
|
-
subtree, reconstructing the shared structure.</p>
|
|
3232
|
-
<p>Folding is optional; it saves space without changing the logical
|
|
3233
|
-
value.</p>
|
|
3234
|
-
<hr />
|
|
3235
|
-
<h2 id="stream-format"><strong>14.8 Stream format</strong></h2>
|
|
3236
|
-
<p>A minimal canonical bitstream consists of:</p>
|
|
3237
|
-
<ol type="1">
|
|
3238
|
-
<li><strong>Header</strong> – type hash (e.g., 8 bytes) identifying the
|
|
3239
|
-
canonical type.</li>
|
|
3240
|
-
<li><strong>Node count</strong> – integer <em>N</em> if DAG encoding is
|
|
3241
|
-
used.</li>
|
|
3242
|
-
<li><strong>Encoded data</strong> – concatenation of all fixed-length
|
|
3243
|
-
union codes and, if folded, node references.</li>
|
|
3244
|
-
</ol>
|
|
3245
|
-
<p>If two systems share the same canonical type table, the bitstream
|
|
3246
|
-
alone is enough to reconstruct the original value.</p>
|
|
3247
|
-
<hr />
|
|
3248
|
-
<h2 id="implementation-sketch"><strong>14.9 Implementation
|
|
3249
|
-
sketch</strong></h2>
|
|
3250
|
-
<p>A compact encoder can be written as follows:</p>
|
|
3251
|
-
<pre><code>procedure encode(node):
|
|
3252
|
-
if node.arity == 0:
|
|
3253
|
-
return
|
|
3254
|
-
if node.arity == 1:
|
|
3255
|
-
write_bits(code_for(node.state, node.tag))
|
|
3256
|
-
encode(node.child[0])
|
|
3257
|
-
else:
|
|
3258
|
-
for each child in node.children:
|
|
3259
|
-
encode(child)</code></pre>
|
|
3260
|
-
<p>The corresponding decoder reverses the process. Both procedures
|
|
3261
|
-
require only the canonical type tables and simple bit operations.</p>
|
|
3262
|
-
<hr />
|
|
3263
|
-
<h2 id="determinism-and-equality"><strong>14.10 Determinism and
|
|
3264
|
-
equality</strong></h2>
|
|
3265
|
-
<p>Because encoding is fully determined by the canonical type and field
|
|
3266
|
-
order, two equal values always produce identical bit sequences.
|
|
3267
|
-
Conversely, decoding the same bit sequence always yields the same
|
|
3268
|
-
tree.</p>
|
|
3269
|
-
<p>This property allows equality comparison by direct byte comparison of
|
|
3270
|
-
serialized forms, without traversing the trees in memory.</p>
|
|
3271
|
-
<hr />
|
|
3272
|
-
<h2 id="summary-12"><strong>14.11 Summary</strong></h2>
|
|
3273
|
-
<ul>
|
|
3274
|
-
<li>Every type’s canonical automaton defines a unique bit-level grammar
|
|
3275
|
-
for its values.</li>
|
|
3276
|
-
<li>Products emit no bits; unions emit fixed-length variant codes.</li>
|
|
3277
|
-
<li>The number of bits required for each state depends only on the
|
|
3278
|
-
number of variants in that state.</li>
|
|
3279
|
-
<li>Optional DAG folding eliminates repeated subtrees.</li>
|
|
3280
|
-
<li>The resulting bitstream is compact, deterministic, and
|
|
3281
|
-
machine-independent.</li>
|
|
3282
|
-
</ul>
|
|
3283
|
-
<h1 id="chapter-15-optimization-and-folding">Chapter 15 — Optimization
|
|
3284
|
-
and Folding</h1>
|
|
3285
|
-
<h2 id="purpose-6"><strong>15.1 Purpose</strong></h2>
|
|
3286
|
-
<p>Optimization in the k compiler is the process of simplifying
|
|
3287
|
-
functions without changing their meaning. The goal is to make the
|
|
3288
|
-
generated code smaller, faster, and easier to verify. Because k is
|
|
3289
|
-
purely functional and has no side effects, optimizations are safe
|
|
3290
|
-
whenever the simplified function is equivalent to the original one.</p>
|
|
3291
|
-
<p>This chapter describes a few basic optimizations that follow directly
|
|
3292
|
-
from the semantics introduced earlier.</p>
|
|
3293
|
-
<hr />
|
|
3294
|
-
<h2 id="constant-folding"><strong>15.2 Constant folding</strong></h2>
|
|
3295
|
-
<p>A <strong>constant</strong> is a function that ignores its input and
|
|
3296
|
-
always produces the same value. If a composition of functions can be
|
|
3297
|
-
evaluated entirely at compile time, it can be replaced by a single
|
|
3298
|
-
constant function.</p>
|
|
3299
|
-
<p>Example:</p>
|
|
3300
|
-
<pre><code>true_bool = {{ } true} $bool;
|
|
3301
|
-
not_true = (true_bool neg);</code></pre>
|
|
3302
|
-
<p>The compiler observes that <code>(true_bool neg)</code> always yields
|
|
3303
|
-
<code>false_bool</code>, so it replaces it with a constant:</p>
|
|
3304
|
-
<pre><code>not_true = {{ } false} $bool;</code></pre>
|
|
3305
|
-
<p>Constant folding removes unnecessary runtime computation.</p>
|
|
3306
|
-
<hr />
|
|
3307
|
-
<h2 id="type-based-simplifications"><strong>15.3 Type-based
|
|
3308
|
-
simplifications</strong></h2>
|
|
3309
|
-
<p>Since type expressions act as identity functions defined only on
|
|
3310
|
-
specific values, they can be eliminated when redundant:</p>
|
|
3311
|
-
<pre><code>$bool $bool f → $bool f</code></pre>
|
|
3312
|
-
<p>If a function’s input or output type is already known from context,
|
|
3313
|
-
repeated checks can be omitted. The compiler ensures that at least one
|
|
3314
|
-
valid check remains to preserve correctness.</p>
|
|
3315
|
-
<hr />
|
|
3316
|
-
<h2 id="inlining"><strong>15.4 Inlining</strong></h2>
|
|
3317
|
-
<p>Inlining replaces a call to a small function by its body. It avoids
|
|
3318
|
-
the overhead of a function call and often exposes further
|
|
3319
|
-
simplifications.</p>
|
|
3320
|
-
<p>Example:</p>
|
|
3321
|
-
<pre><code>id = ();
|
|
3322
|
-
f = (id g);</code></pre>
|
|
3323
|
-
<p>Because <code>id</code> is the identity function, <code>(id g)</code>
|
|
3324
|
-
is equivalent to <code>g</code>. Inlining removes the useless call.</p>
|
|
3325
|
-
<p>For larger functions, inlining is applied selectively—only when it
|
|
3326
|
-
shortens the resulting code or eliminates intermediate values.</p>
|
|
3327
|
-
<hr />
|
|
3328
|
-
<h2 id="dead-branch-elimination"><strong>15.5 Dead-branch
|
|
3329
|
-
elimination</strong></h2>
|
|
3330
|
-
<p>In a union composition <code><f, g></code>, if type analysis
|
|
3331
|
-
shows that the input type can only satisfy the first branch, the second
|
|
3332
|
-
branch can never be defined and is removed.</p>
|
|
3333
|
-
<p>Example:</p>
|
|
3334
|
-
<pre><code>$bool = < {} true, {} false >;
|
|
3335
|
-
f = $bool < .true {{ } false} >;</code></pre>
|
|
3336
|
-
<p>Here, since <code>$bool</code> restricts the input to only the two
|
|
3337
|
-
variants <code>true</code> and <code>false</code>, and the second
|
|
3338
|
-
variant <code>.false</code> is not handled, the compiler infers that
|
|
3339
|
-
<code>f</code> is undefined for <code>.false</code> and simplifies the
|
|
3340
|
-
code accordingly.</p>
|
|
3341
|
-
<p>Dead-branch elimination keeps the generated control flow minimal.</p>
|
|
3342
|
-
<hr />
|
|
3343
|
-
<h2 id="common-subexpression-elimination"><strong>15.6 Common
|
|
3344
|
-
subexpression elimination</strong></h2>
|
|
3345
|
-
<p>If the same partial function is applied multiple times to the same
|
|
3346
|
-
input, the result will always be the same. The compiler can compute it
|
|
3347
|
-
once and reuse the result.</p>
|
|
3348
|
-
<p>Example:</p>
|
|
3349
|
-
<pre><code>{ .x .y, .x .z }</code></pre>
|
|
3350
|
-
<p>Both fields start with the projection <code>.x</code>. The compiler
|
|
3351
|
-
computes <code>.x</code> once, stores the result, and reuses it for
|
|
3352
|
-
<code>.y</code> and <code>.z</code>. This optimization reduces repeated
|
|
3353
|
-
traversal of the same input structure.</p>
|
|
3354
|
-
<hr />
|
|
3355
|
-
<h2 id="canonical-folding"><strong>15.7 Canonical folding</strong></h2>
|
|
3356
|
-
<p>During evaluation, many values share identical subtrees. A
|
|
3357
|
-
<strong>folding pass</strong> replaces identical subtrees by shared
|
|
3358
|
-
nodes, forming a minimal DAG (directed acyclic graph).</p>
|
|
3359
|
-
<p>At compile time, folding may also apply to constant expressions. If
|
|
3360
|
-
two constant subtrees are identical, they are merged and stored as a
|
|
3361
|
-
single global node.</p>
|
|
3362
|
-
<p>This process ensures that structural equality corresponds to pointer
|
|
3363
|
-
equality: two values are identical if they share the same root node.</p>
|
|
3364
|
-
<hr />
|
|
3365
|
-
<h2 id="function-canonicalization"><strong>15.8 Function
|
|
3366
|
-
canonicalization</strong></h2>
|
|
3367
|
-
<p>Every function can be normalized by expanding all type aliases,
|
|
3368
|
-
inlining trivial definitions, and folding identical subfunctions. The
|
|
3369
|
-
normalized form of a function depends only on its semantics, not on the
|
|
3370
|
-
way it was written.</p>
|
|
3371
|
-
<p>A stable hash computed from this canonical representation serves as a
|
|
3372
|
-
permanent identifier for the function, just as type hashes identify
|
|
3373
|
-
canonical types.</p>
|
|
3374
|
-
<p>This property is essential for the schema registry described in the
|
|
3375
|
-
next chapter.</p>
|
|
3376
|
-
<hr />
|
|
3377
|
-
<h2 id="runtime-simplifications"><strong>15.9 Runtime
|
|
3378
|
-
simplifications</strong></h2>
|
|
3379
|
-
<p>At runtime, additional micro-optimizations are possible:</p>
|
|
3380
|
-
<ul>
|
|
3381
|
-
<li><strong>Arena reuse:</strong> allocate nodes in a memory region that
|
|
3382
|
-
is cleared after each function call.</li>
|
|
3383
|
-
<li><strong>Hash-consing:</strong> maintain a small table of recently
|
|
3384
|
-
created nodes to reuse identical ones automatically.</li>
|
|
3385
|
-
<li><strong>Shortcut constants:</strong> return pointers to global
|
|
3386
|
-
constants instead of allocating new copies for unit or boolean
|
|
3387
|
-
values.</li>
|
|
3388
|
-
</ul>
|
|
3389
|
-
<p>Such optimizations reduce memory usage without changing program
|
|
3390
|
-
behavior.</p>
|
|
3391
|
-
<hr />
|
|
3392
|
-
<h2 id="equivalence-and-correctness"><strong>15.10 Equivalence and
|
|
3393
|
-
correctness</strong></h2>
|
|
3394
|
-
<p>Each optimization must preserve <em>semantic equivalence</em>: for
|
|
3395
|
-
every input, the optimized function must be defined for exactly the same
|
|
3396
|
-
values and must return the same result when defined.</p>
|
|
3397
|
-
<p>Because k’s semantics are purely functional, equivalence can be
|
|
3398
|
-
tested mechanically by comparing evaluation results on all finite inputs
|
|
3399
|
-
of a small type, or by structural reasoning when types are infinite.</p>
|
|
3400
|
-
<hr />
|
|
3401
|
-
<h2 id="summary-13"><strong>15.11 Summary</strong></h2>
|
|
3402
|
-
<ul>
|
|
3403
|
-
<li>Optimization in k relies on algebraic properties of pure
|
|
3404
|
-
functions.</li>
|
|
3405
|
-
<li>Common transformations include constant folding, inlining,
|
|
3406
|
-
dead-branch elimination, and subexpression reuse.</li>
|
|
3407
|
-
<li>Folding shared subtrees yields compact DAG representations of
|
|
3408
|
-
values.</li>
|
|
3409
|
-
<li>Canonical function forms allow stable hashing and reproducible
|
|
3410
|
-
compilation results.</li>
|
|
3411
|
-
<li>All optimizations preserve exact semantic behavior.</li>
|
|
3412
|
-
</ul>
|
|
3413
|
-
<h1 id="chapter-16-toward-a-universal-schema-registry">Chapter 16 —
|
|
3414
|
-
Toward a Universal Schema Registry</h1>
|
|
3415
|
-
<h2 id="motivation-1"><strong>16.1 Motivation</strong></h2>
|
|
3416
|
-
<p>Every canonical type and function in k has a unique structural form
|
|
3417
|
-
and a stable hash. These hashes can serve as global identifiers. A
|
|
3418
|
-
registry that maps such identifiers to definitions allows programs and
|
|
3419
|
-
systems to exchange schemas and functions safely and reproducibly.</p>
|
|
3420
|
-
<hr />
|
|
3421
|
-
<h2 id="basic-structure"><strong>16.2 Basic structure</strong></h2>
|
|
3422
|
-
<p>A schema registry stores entries of two kinds:</p>
|
|
3423
|
-
<table>
|
|
3424
|
-
<colgroup>
|
|
3425
|
-
<col style="width: 16%" />
|
|
3426
|
-
<col style="width: 83%" />
|
|
3427
|
-
</colgroup>
|
|
3428
|
-
<thead>
|
|
3429
|
-
<tr>
|
|
3430
|
-
<th>Kind</th>
|
|
3431
|
-
<th>Example content</th>
|
|
3432
|
-
</tr>
|
|
3433
|
-
</thead>
|
|
3434
|
-
<tbody>
|
|
3435
|
-
<tr>
|
|
3436
|
-
<td><strong>Type</strong></td>
|
|
3437
|
-
<td>canonical automaton text for a type hash</td>
|
|
3438
|
-
</tr>
|
|
3439
|
-
<tr>
|
|
3440
|
-
<td><strong>Function</strong></td>
|
|
3441
|
-
<td>canonical IR or serialized representation for a function hash</td>
|
|
3442
|
-
</tr>
|
|
3443
|
-
</tbody>
|
|
3444
|
-
</table>
|
|
3445
|
-
<p>Each entry is immutable. New versions are added as new hashes.</p>
|
|
3446
|
-
<hr />
|
|
3447
|
-
<h2 id="key-operations"><strong>16.3 Key operations</strong></h2>
|
|
3448
|
-
<ol type="1">
|
|
3449
|
-
<li><strong>Lookup by hash</strong> — return the canonical
|
|
3450
|
-
definition.</li>
|
|
3451
|
-
<li><strong>Lookup by shape</strong> — search for functions with given
|
|
3452
|
-
input/output type hashes.</li>
|
|
3453
|
-
<li><strong>Verification</strong> — ensure that two parties share the
|
|
3454
|
-
same canonical form before exchanging values.</li>
|
|
3455
|
-
</ol>
|
|
3456
|
-
<p>These operations can be implemented as simple key–value queries.</p>
|
|
3457
|
-
<hr />
|
|
3458
|
-
<h2 id="example-format"><strong>16.4 Example format</strong></h2>
|
|
3459
|
-
<p>A minimal JSON entry:</p>
|
|
3460
|
-
<div class="sourceCode" id="cb119"><pre
|
|
3461
|
-
class="sourceCode json"><code class="sourceCode json"><span id="cb119-1"><a href="#cb119-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
|
3462
|
-
<span id="cb119-2"><a href="#cb119-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"hash"</span><span class="fu">:</span> <span class="st">"C0ABCDEF"</span><span class="fu">,</span></span>
|
|
3463
|
-
<span id="cb119-3"><a href="#cb119-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"kind"</span><span class="fu">:</span> <span class="st">"type"</span><span class="fu">,</span></span>
|
|
3464
|
-
<span id="cb119-4"><a href="#cb119-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"definition"</span><span class="fu">:</span> <span class="st">"$C0=<C0</span><span class="ch">\"</span><span class="st">0</span><span class="ch">\"</span><span class="st">,C0</span><span class="ch">\"</span><span class="st">1</span><span class="ch">\"</span><span class="st">,C1</span><span class="ch">\"</span><span class="st">_</span><span class="ch">\"</span><span class="st">>;$C1={};"</span></span>
|
|
3465
|
-
<span id="cb119-5"><a href="#cb119-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
|
3466
|
-
<p>or for a function:</p>
|
|
3467
|
-
<div class="sourceCode" id="cb120"><pre
|
|
3468
|
-
class="sourceCode json"><code class="sourceCode json"><span id="cb120-1"><a href="#cb120-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
|
3469
|
-
<span id="cb120-2"><a href="#cb120-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"hash"</span><span class="fu">:</span> <span class="st">"F7B1A2"</span><span class="fu">,</span></span>
|
|
3470
|
-
<span id="cb120-3"><a href="#cb120-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"kind"</span><span class="fu">:</span> <span class="st">"function"</span><span class="fu">,</span></span>
|
|
3471
|
-
<span id="cb120-4"><a href="#cb120-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"input"</span><span class="fu">:</span> <span class="st">"C0ABCDEF"</span><span class="fu">,</span></span>
|
|
3472
|
-
<span id="cb120-5"><a href="#cb120-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"output"</span><span class="fu">:</span> <span class="st">"C9FFF1"</span><span class="fu">,</span></span>
|
|
3473
|
-
<span id="cb120-6"><a href="#cb120-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">"ir"</span><span class="fu">:</span> <span class="st">"SEQ [PROJECT x, CONST true]"</span></span>
|
|
3474
|
-
<span id="cb120-7"><a href="#cb120-7" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
|
3475
|
-
<hr />
|
|
3476
|
-
<h2 id="uses"><strong>16.5 Uses</strong></h2>
|
|
3477
|
-
<ul>
|
|
3478
|
-
<li>Preventing schema mismatches in distributed systems.</li>
|
|
3479
|
-
<li>Deduplicating identical definitions across projects.</li>
|
|
3480
|
-
<li>Enabling reproducible builds where all types and functions are
|
|
3481
|
-
referenced by hash.</li>
|
|
3482
|
-
</ul>
|
|
3483
|
-
<hr />
|
|
3484
|
-
<h2 id="summary-14"><strong>16.6 Summary</strong></h2>
|
|
3485
|
-
<ul>
|
|
3486
|
-
<li>Canonical types and functions can be globally identified by stable
|
|
3487
|
-
hashes.</li>
|
|
3488
|
-
<li>A simple registry provides lookup and verification of these
|
|
3489
|
-
definitions.</li>
|
|
3490
|
-
<li>Such registries make k programs portable, self-describing, and safe
|
|
3491
|
-
to share between systems.</li>
|
|
3492
|
-
</ul>
|
|
3493
|
-
<h1 id="appendix-a-implementing-a-prototype-compiler-in-python">Appendix
|
|
3494
|
-
A — Implementing a Prototype Compiler in Python</h1>
|
|
3495
|
-
<h2 id="a.1-purpose"><strong>A.1 Purpose</strong></h2>
|
|
3496
|
-
<p>This appendix outlines how to implement a simple, working prototype
|
|
3497
|
-
of the k compiler in Python. The goal is to let the reader experiment
|
|
3498
|
-
with parsing, type normalization, and LLVM code generation using only
|
|
3499
|
-
standard tools and a few small libraries. The prototype does not need to
|
|
3500
|
-
support optimization or a full runtime—only the basic translation
|
|
3501
|
-
pipeline.</p>
|
|
3502
|
-
<hr />
|
|
3503
|
-
<h2 id="a.2-required-environment"><strong>A.2 Required
|
|
3504
|
-
environment</strong></h2>
|
|
3505
|
-
<p>Install:</p>
|
|
3506
|
-
<div class="sourceCode" id="cb121"><pre
|
|
3507
|
-
class="sourceCode bash"><code class="sourceCode bash"><span id="cb121-1"><a href="#cb121-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> venv kenv</span>
|
|
3508
|
-
<span id="cb121-2"><a href="#cb121-2" aria-hidden="true" tabindex="-1"></a><span class="bu">source</span> kenv/bin/activate</span>
|
|
3509
|
-
<span id="cb121-3"><a href="#cb121-3" aria-hidden="true" tabindex="-1"></a><span class="ex">pip</span> install llvmlite</span></code></pre></div>
|
|
3510
|
-
<p><code>llvmlite</code> provides an interface to LLVM for code
|
|
3511
|
-
generation. No additional dependencies are required.</p>
|
|
3512
|
-
<hr />
|
|
3513
|
-
<h2 id="a.3-recommended-directory-structure"><strong>A.3 Recommended
|
|
3514
|
-
directory structure</strong></h2>
|
|
3515
|
-
<pre><code>k-compiler/
|
|
3516
|
-
├── main.py # command-line driver
|
|
3517
|
-
├── parser.py # converts source text to AST
|
|
3518
|
-
├── types.py # canonical type construction
|
|
3519
|
-
├── normalize.py # filter resolution and typing
|
|
3520
|
-
├── ir.py # intermediate representation
|
|
3521
|
-
├── codegen.py # translation from IR to LLVM
|
|
3522
|
-
├── runtime.ll # minimal runtime in LLVM
|
|
3523
|
-
└── examples/ # sample k programs</code></pre>
|
|
3524
|
-
<p>Each module is small and focused on one task.</p>
|
|
3525
|
-
<hr />
|
|
3526
|
-
<h2 id="a.4-the-ast"><strong>A.4 The AST</strong></h2>
|
|
3527
|
-
<p>Represent the language syntax with Python classes:</p>
|
|
3528
|
-
<div class="sourceCode" id="cb123"><pre
|
|
3529
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb123-1"><a href="#cb123-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Expr: <span class="cf">pass</span></span>
|
|
3530
|
-
<span id="cb123-2"><a href="#cb123-2" aria-hidden="true" tabindex="-1"></a></span>
|
|
3531
|
-
<span id="cb123-3"><a href="#cb123-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Composition(Expr):</span>
|
|
3532
|
-
<span id="cb123-4"><a href="#cb123-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
|
|
3533
|
-
<span id="cb123-5"><a href="#cb123-5" aria-hidden="true" tabindex="-1"></a></span>
|
|
3534
|
-
<span id="cb123-6"><a href="#cb123-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Product(Expr):</span>
|
|
3535
|
-
<span id="cb123-7"><a href="#cb123-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, fields): <span class="va">self</span>.fields <span class="op">=</span> fields <span class="co"># [(label, expr), ...]</span></span>
|
|
3536
|
-
<span id="cb123-8"><a href="#cb123-8" aria-hidden="true" tabindex="-1"></a></span>
|
|
3537
|
-
<span id="cb123-9"><a href="#cb123-9" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Union(Expr):</span>
|
|
3538
|
-
<span id="cb123-10"><a href="#cb123-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, options): <span class="va">self</span>.options <span class="op">=</span> options <span class="co"># [expr, ...]</span></span>
|
|
3539
|
-
<span id="cb123-11"><a href="#cb123-11" aria-hidden="true" tabindex="-1"></a></span>
|
|
3540
|
-
<span id="cb123-12"><a href="#cb123-12" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Projection(Expr):</span>
|
|
3541
|
-
<span id="cb123-13"><a href="#cb123-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, label): <span class="va">self</span>.label <span class="op">=</span> label</span>
|
|
3542
|
-
<span id="cb123-14"><a href="#cb123-14" aria-hidden="true" tabindex="-1"></a></span>
|
|
3543
|
-
<span id="cb123-15"><a href="#cb123-15" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Constant(Expr):</span>
|
|
3544
|
-
<span id="cb123-16"><a href="#cb123-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, name): <span class="va">self</span>.name <span class="op">=</span> name</span></code></pre></div>
|
|
3545
|
-
<p>The parser builds these objects from source text.</p>
|
|
3546
|
-
<hr />
|
|
3547
|
-
<h2 id="a.5-type-normalization"><strong>A.5 Type
|
|
3548
|
-
normalization</strong></h2>
|
|
3549
|
-
<p>Maintain canonical type states as small Python objects:</p>
|
|
3550
|
-
<div class="sourceCode" id="cb124"><pre
|
|
3551
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb124-1"><a href="#cb124-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> TypeState:</span>
|
|
3552
|
-
<span id="cb124-2"><a href="#cb124-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, kind, transitions):</span>
|
|
3553
|
-
<span id="cb124-3"><a href="#cb124-3" aria-hidden="true" tabindex="-1"></a> <span class="va">self</span>.kind <span class="op">=</span> kind <span class="co"># 'product' or 'union'</span></span>
|
|
3554
|
-
<span id="cb124-4"><a href="#cb124-4" aria-hidden="true" tabindex="-1"></a> <span class="va">self</span>.transitions <span class="op">=</span> transitions <span class="co"># [(label, next_state)]</span></span></code></pre></div>
|
|
3555
|
-
<p>Normalization expands type aliases and assigns numeric state IDs
|
|
3556
|
-
(<code>C0</code>, <code>C1</code>, …). For a prototype, a simple
|
|
3557
|
-
structural hash (using <code>json.dumps</code>) can serve as the
|
|
3558
|
-
canonical identifier.</p>
|
|
3559
|
-
<hr />
|
|
3560
|
-
<h2 id="a.6-intermediate-representation"><strong>A.6 Intermediate
|
|
3561
|
-
representation</strong></h2>
|
|
3562
|
-
<p>Represent IR instructions as simple tuples or small classes:</p>
|
|
3563
|
-
<div class="sourceCode" id="cb125"><pre
|
|
3564
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb125-1"><a href="#cb125-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Project: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, label): <span class="va">self</span>.label <span class="op">=</span> label</span>
|
|
3565
|
-
<span id="cb125-2"><a href="#cb125-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Const: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, node): <span class="va">self</span>.node <span class="op">=</span> node</span>
|
|
3566
|
-
<span id="cb125-3"><a href="#cb125-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Seq: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
|
|
3567
|
-
<span id="cb125-4"><a href="#cb125-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> UnionIR: <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parts): <span class="va">self</span>.parts <span class="op">=</span> parts</span>
|
|
3568
|
-
<span id="cb125-5"><a href="#cb125-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> ProductIR:<span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, fields):<span class="va">self</span>.fields <span class="op">=</span> fields</span></code></pre></div>
|
|
3569
|
-
<p>A recursive function converts an AST expression into IR following
|
|
3570
|
-
Chapter 10.</p>
|
|
3571
|
-
<hr />
|
|
3572
|
-
<h2 id="a.7-generating-llvm-code"><strong>A.7 Generating LLVM
|
|
3573
|
-
code</strong></h2>
|
|
3574
|
-
<p>Using <code>llvmlite.ir</code>, create one LLVM function per compiled
|
|
3575
|
-
function:</p>
|
|
3576
|
-
<div class="sourceCode" id="cb126"><pre
|
|
3577
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb126-1"><a href="#cb126-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> llvmlite <span class="im">import</span> ir</span>
|
|
3578
|
-
<span id="cb126-2"><a href="#cb126-2" aria-hidden="true" tabindex="-1"></a></span>
|
|
3579
|
-
<span id="cb126-3"><a href="#cb126-3" aria-hidden="true" tabindex="-1"></a>mod <span class="op">=</span> ir.Module(name<span class="op">=</span><span class="st">"k"</span>)</span>
|
|
3580
|
-
<span id="cb126-4"><a href="#cb126-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
3581
|
-
<span id="cb126-5"><a href="#cb126-5" aria-hidden="true" tabindex="-1"></a><span class="co"># LLVM type definitions</span></span>
|
|
3582
|
-
<span id="cb126-6"><a href="#cb126-6" aria-hidden="true" tabindex="-1"></a>KNodePtr <span class="op">=</span> ir.PointerType(ir.IntType(<span class="dv">8</span>))</span>
|
|
3583
|
-
<span id="cb126-7"><a href="#cb126-7" aria-hidden="true" tabindex="-1"></a>KVal <span class="op">=</span> ir.LiteralStructType([KNodePtr])</span>
|
|
3584
|
-
<span id="cb126-8"><a href="#cb126-8" aria-hidden="true" tabindex="-1"></a>KOpt <span class="op">=</span> ir.LiteralStructType([ir.IntType(<span class="dv">1</span>), KVal])</span>
|
|
3585
|
-
<span id="cb126-9"><a href="#cb126-9" aria-hidden="true" tabindex="-1"></a></span>
|
|
3586
|
-
<span id="cb126-10"><a href="#cb126-10" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> emit_function(name, ir_expr):</span>
|
|
3587
|
-
<span id="cb126-11"><a href="#cb126-11" aria-hidden="true" tabindex="-1"></a> fn_type <span class="op">=</span> ir.FunctionType(KOpt, [KVal])</span>
|
|
3588
|
-
<span id="cb126-12"><a href="#cb126-12" aria-hidden="true" tabindex="-1"></a> fn <span class="op">=</span> ir.Function(mod, fn_type, name<span class="op">=</span>name)</span>
|
|
3589
|
-
<span id="cb126-13"><a href="#cb126-13" aria-hidden="true" tabindex="-1"></a> block <span class="op">=</span> fn.append_basic_block(<span class="st">'entry'</span>)</span>
|
|
3590
|
-
<span id="cb126-14"><a href="#cb126-14" aria-hidden="true" tabindex="-1"></a> builder <span class="op">=</span> ir.IRBuilder(block)</span>
|
|
3591
|
-
<span id="cb126-15"><a href="#cb126-15" aria-hidden="true" tabindex="-1"></a> <span class="co"># translate ir_expr recursively into builder calls</span></span>
|
|
3592
|
-
<span id="cb126-16"><a href="#cb126-16" aria-hidden="true" tabindex="-1"></a> builder.ret(ir.Constant(KOpt, (ir.Constant(ir.IntType(<span class="dv">1</span>), <span class="dv">0</span>),</span>
|
|
3593
|
-
<span id="cb126-17"><a href="#cb126-17" aria-hidden="true" tabindex="-1"></a> ir.Constant(KVal, ir.Constant(KNodePtr, <span class="va">None</span>)))))</span></code></pre></div>
|
|
3594
|
-
<p>The translation patterns follow those described in Chapter 12. Each
|
|
3595
|
-
IR node is emitted as a call or conditional block using
|
|
3596
|
-
<code>builder.call</code>, <code>builder.if_then</code>, and so on.</p>
|
|
3597
|
-
<hr />
|
|
3598
|
-
<h2 id="a.8-minimal-runtime"><strong>A.8 Minimal runtime</strong></h2>
|
|
3599
|
-
<p>Write a minimal <code>runtime.ll</code> that defines stubs for:</p>
|
|
3600
|
-
<div class="sourceCode" id="cb127"><pre
|
|
3601
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb127-1"><a href="#cb127-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KOpt</span> <span class="fu">@k_project</span>(<span class="fu">%KVal</span> <span class="fu">%v</span>, <span class="dt">i32</span> <span class="fu">%label</span>)</span>
|
|
3602
|
-
<span id="cb127-2"><a href="#cb127-2" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_product</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%n</span>, <span class="fu">%KVal</span>* <span class="fu">%children</span>)</span>
|
|
3603
|
-
<span id="cb127-3"><a href="#cb127-3" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KVal</span> <span class="fu">@k_make_union</span>(<span class="dt">i32</span> <span class="fu">%state</span>, <span class="dt">i32</span> <span class="fu">%tag</span>, <span class="fu">%KVal</span> <span class="fu">%child</span>)</span></code></pre></div>
|
|
3604
|
-
<p>These can simply return placeholder constants for testing. Later,
|
|
3605
|
-
they can be replaced with the real runtime implemented in C.</p>
|
|
3606
|
-
<hr />
|
|
3607
|
-
<h2 id="a.9-putting-it-together"><strong>A.9 Putting it
|
|
3608
|
-
together</strong></h2>
|
|
3609
|
-
<p>A small driver script (<code>main.py</code>) can compile a file and
|
|
3610
|
-
emit LLVM text:</p>
|
|
3611
|
-
<div class="sourceCode" id="cb128"><pre
|
|
3612
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb128-1"><a href="#cb128-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> parser, normalize, ir, codegen</span>
|
|
3613
|
-
<span id="cb128-2"><a href="#cb128-2" aria-hidden="true" tabindex="-1"></a></span>
|
|
3614
|
-
<span id="cb128-3"><a href="#cb128-3" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> compile_file(path):</span>
|
|
3615
|
-
<span id="cb128-4"><a href="#cb128-4" aria-hidden="true" tabindex="-1"></a> src <span class="op">=</span> <span class="bu">open</span>(path).read()</span>
|
|
3616
|
-
<span id="cb128-5"><a href="#cb128-5" aria-hidden="true" tabindex="-1"></a> ast <span class="op">=</span> parser.parse(src)</span>
|
|
3617
|
-
<span id="cb128-6"><a href="#cb128-6" aria-hidden="true" tabindex="-1"></a> typed <span class="op">=</span> normalize.process(ast)</span>
|
|
3618
|
-
<span id="cb128-7"><a href="#cb128-7" aria-hidden="true" tabindex="-1"></a> ir_tree <span class="op">=</span> ir.from_ast(typed)</span>
|
|
3619
|
-
<span id="cb128-8"><a href="#cb128-8" aria-hidden="true" tabindex="-1"></a> llvm_module <span class="op">=</span> codegen.emit(ir_tree)</span>
|
|
3620
|
-
<span id="cb128-9"><a href="#cb128-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="bu">str</span>(llvm_module))</span></code></pre></div>
|
|
3621
|
-
<p>Run:</p>
|
|
3622
|
-
<div class="sourceCode" id="cb129"><pre
|
|
3623
|
-
class="sourceCode bash"><code class="sourceCode bash"><span id="cb129-1"><a href="#cb129-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python</span> main.py examples/neg.k <span class="op">></span> neg.ll</span>
|
|
3624
|
-
<span id="cb129-2"><a href="#cb129-2" aria-hidden="true" tabindex="-1"></a><span class="fu">clang</span> <span class="at">-O2</span> neg.ll runtime.ll <span class="at">-o</span> neg</span></code></pre></div>
|
|
3625
|
-
<hr />
|
|
3626
|
-
<h2 id="a.10-suggested-extensions"><strong>A.10 Suggested
|
|
3627
|
-
extensions</strong></h2>
|
|
3628
|
-
<ol type="1">
|
|
3629
|
-
<li>Implement the runtime functions in Python for quick testing.</li>
|
|
3630
|
-
<li>Add a textual REPL that reads a k expression and prints its IR.</li>
|
|
3631
|
-
<li>Integrate a simple interpreter to compare interpreter and compiled
|
|
3632
|
-
results.</li>
|
|
3633
|
-
<li>Use hashing of canonical forms to name generated LLVM
|
|
3634
|
-
functions.</li>
|
|
3635
|
-
</ol>
|
|
3636
|
-
<hr />
|
|
3637
|
-
<h2 id="a.11-summary"><strong>A.11 Summary</strong></h2>
|
|
3638
|
-
<p>A prototype compiler can be realized in fewer than a thousand lines
|
|
3639
|
-
of Python. It can parse k definitions, construct canonical types,
|
|
3640
|
-
translate expressions into IR, and generate valid LLVM code. Such a
|
|
3641
|
-
prototype is enough to experiment with all ideas presented in this
|
|
3642
|
-
textbook and to verify the semantics of the k language in practice.</p>
|
|
3643
|
-
<hr />
|
|
3644
|
-
<h1
|
|
3645
|
-
id="appendix-b-incorporating-external-predefined-types-and-functions">Appendix
|
|
3646
|
-
B — Incorporating External Predefined Types and Functions</h1>
|
|
3647
|
-
<h2 id="b.1-purpose"><strong>B.1 Purpose</strong></h2>
|
|
3648
|
-
<p>The k language is intentionally minimal. Nevertheless, real systems
|
|
3649
|
-
often need to interact with data types and operations defined outside of
|
|
3650
|
-
k—for example, numeric values, text, or platform-specific constants.
|
|
3651
|
-
This appendix explains how external predefined types and functions can
|
|
3652
|
-
be introduced into a k compiler without changing the language
|
|
3653
|
-
itself.</p>
|
|
3654
|
-
<hr />
|
|
3655
|
-
<h2 id="b.2-external-types"><strong>B.2 External types</strong></h2>
|
|
3656
|
-
<p>An <strong>external type</strong> is a canonical type that is
|
|
3657
|
-
<em>not</em> expressed through k’s own product-and-union syntax but is
|
|
3658
|
-
known to the compiler through registration.</p>
|
|
3659
|
-
<p>Each external type has:</p>
|
|
3660
|
-
<table>
|
|
3661
|
-
<colgroup>
|
|
3662
|
-
<col style="width: 21%" />
|
|
3663
|
-
<col style="width: 78%" />
|
|
3664
|
-
</colgroup>
|
|
3665
|
-
<thead>
|
|
3666
|
-
<tr>
|
|
3667
|
-
<th>Field</th>
|
|
3668
|
-
<th>Description</th>
|
|
3669
|
-
</tr>
|
|
3670
|
-
</thead>
|
|
3671
|
-
<tbody>
|
|
3672
|
-
<tr>
|
|
3673
|
-
<td><strong>Name</strong></td>
|
|
3674
|
-
<td>symbolic name (e.g., <code>$int</code>, <code>$string</code>)</td>
|
|
3675
|
-
</tr>
|
|
3676
|
-
<tr>
|
|
3677
|
-
<td><strong>Hash</strong></td>
|
|
3678
|
-
<td>unique stable identifier, just like canonical types</td>
|
|
3679
|
-
</tr>
|
|
3680
|
-
<tr>
|
|
3681
|
-
<td><strong>Runtime kind</strong></td>
|
|
3682
|
-
<td>how the value is stored in memory (pointer, immediate integer,
|
|
3683
|
-
etc.)</td>
|
|
3684
|
-
</tr>
|
|
3685
|
-
<tr>
|
|
3686
|
-
<td><strong>Adapter functions</strong></td>
|
|
3687
|
-
<td>conversion between the external representation and the standard
|
|
3688
|
-
<code>KNode</code> tree</td>
|
|
3689
|
-
</tr>
|
|
3690
|
-
</tbody>
|
|
3691
|
-
</table>
|
|
3692
|
-
<p>Example registry entry:</p>
|
|
3693
|
-
<div class="sourceCode" id="cb130"><pre
|
|
3694
|
-
class="sourceCode json"><code class="sourceCode json"><span id="cb130-1"><a href="#cb130-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
|
3695
|
-
<span id="cb130-2"><a href="#cb130-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"hash"</span><span class="fu">:</span> <span class="st">"E001"</span><span class="fu">,</span></span>
|
|
3696
|
-
<span id="cb130-3"><a href="#cb130-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"kind"</span><span class="fu">:</span> <span class="st">"type"</span><span class="fu">,</span></span>
|
|
3697
|
-
<span id="cb130-4"><a href="#cb130-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"external"</span><span class="fu">:</span> <span class="kw">true</span><span class="fu">,</span></span>
|
|
3698
|
-
<span id="cb130-5"><a href="#cb130-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"name"</span><span class="fu">:</span> <span class="st">"$int"</span><span class="fu">,</span></span>
|
|
3699
|
-
<span id="cb130-6"><a href="#cb130-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">"runtime_kind"</span><span class="fu">:</span> <span class="st">"primitive_i64"</span></span>
|
|
3700
|
-
<span id="cb130-7"><a href="#cb130-7" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
|
3701
|
-
<p>The compiler treats such a type as an atomic node, represented
|
|
3702
|
-
internally as a single <code>KNode</code> with <code>arity = 0</code>
|
|
3703
|
-
but tagged as <em>external</em>.</p>
|
|
3704
|
-
<hr />
|
|
3705
|
-
<h2 id="b.3-external-constructors"><strong>B.3 External
|
|
3706
|
-
constructors</strong></h2>
|
|
3707
|
-
<p>External types may provide special constructors or constants. For
|
|
3708
|
-
example, <code>$int</code> might include predefined constant
|
|
3709
|
-
functions:</p>
|
|
3710
|
-
<pre><code>zero = {} $int;
|
|
3711
|
-
one = {} $int;</code></pre>
|
|
3712
|
-
<p>At compile time these appear as constant functions returning fixed
|
|
3713
|
-
external nodes provided by the runtime.</p>
|
|
3714
|
-
<hr />
|
|
3715
|
-
<h2 id="b.4-external-functions"><strong>B.4 External
|
|
3716
|
-
functions</strong></h2>
|
|
3717
|
-
<p>External functions are partial functions implemented outside of k but
|
|
3718
|
-
declared inside a k program. They have known input and output types,
|
|
3719
|
-
possibly external.</p>
|
|
3720
|
-
<p>Declaration syntax:</p>
|
|
3721
|
-
<pre><code>extern add : $int $int → $int;
|
|
3722
|
-
extern less : $int $int → $bool;</code></pre>
|
|
3723
|
-
<p>At compile time the compiler records the signature and associates it
|
|
3724
|
-
with a runtime symbol name such as <code>k_ext_add</code>.</p>
|
|
3725
|
-
<p>When generating code, each external call becomes a standard function
|
|
3726
|
-
call following the ABI:</p>
|
|
3727
|
-
<div class="sourceCode" id="cb133"><pre
|
|
3728
|
-
class="sourceCode llvm"><code class="sourceCode llvm"><span id="cb133-1"><a href="#cb133-1" aria-hidden="true" tabindex="-1"></a><span class="kw">declare</span> <span class="fu">%KOpt</span> <span class="fu">@k_ext_add</span>(<span class="fu">%KVal</span> <span class="fu">%a</span>, <span class="fu">%KVal</span> <span class="fu">%b</span>)</span></code></pre></div>
|
|
3729
|
-
<p>The runtime library provides these implementations in a native
|
|
3730
|
-
language (C, C++, Rust, etc.).</p>
|
|
3731
|
-
<hr />
|
|
3732
|
-
<h2 id="b.5-integration-with-canonical-types"><strong>B.5 Integration
|
|
3733
|
-
with canonical types</strong></h2>
|
|
3734
|
-
<p>External types are integrated into the canonical system as <em>leaf
|
|
3735
|
-
states</em>. They can appear as components in products or unions just
|
|
3736
|
-
like built-in ones.</p>
|
|
3737
|
-
<p>Example:</p>
|
|
3738
|
-
<pre><code>$point = { $int x, $int y };</code></pre>
|
|
3739
|
-
<p>Canonical form:</p>
|
|
3740
|
-
<pre><code>$C0 = { C1 "x", C1 "y" };
|
|
3741
|
-
$C1 = external $int;</code></pre>
|
|
3742
|
-
<p>This allows normal serialization and type comparison; the external
|
|
3743
|
-
leaf is treated as opaque but identified by its hash.</p>
|
|
3744
|
-
<hr />
|
|
3745
|
-
<h2 id="b.6-serialization-and-external-values"><strong>B.6 Serialization
|
|
3746
|
-
and external values</strong></h2>
|
|
3747
|
-
<p>During serialization, an external node is encoded by:</p>
|
|
3748
|
-
<ol type="1">
|
|
3749
|
-
<li>Its type hash (to indicate which external kind it represents).</li>
|
|
3750
|
-
<li>A binary blob produced by a runtime-supplied encoder for that
|
|
3751
|
-
type.</li>
|
|
3752
|
-
</ol>
|
|
3753
|
-
<p>Deserialization reverses the process using the corresponding decoder.
|
|
3754
|
-
All external codecs must be deterministic and version-stable to preserve
|
|
3755
|
-
canonical equality.</p>
|
|
3756
|
-
<hr />
|
|
3757
|
-
<h2 id="b.7-example"><strong>B.7 Example</strong></h2>
|
|
3758
|
-
<p>Suppose we introduce <code>$int</code> and external function
|
|
3759
|
-
<code>add</code>:</p>
|
|
3760
|
-
<pre><code>$pair_int = { $int a, $int b };
|
|
3761
|
-
sum = { .a x, .b y } (add x y);</code></pre>
|
|
3762
|
-
<p>The compiler generates code that:</p>
|
|
3763
|
-
<ul>
|
|
3764
|
-
<li>projects fields <code>.a</code> and <code>.b</code>,</li>
|
|
3765
|
-
<li>passes them as <code>KVal</code> pointers to
|
|
3766
|
-
<code>@k_ext_add</code>,</li>
|
|
3767
|
-
<li>and returns the result as a new <code>$int</code> node.</li>
|
|
3768
|
-
</ul>
|
|
3769
|
-
<p>All logic outside arithmetic remains standard k code.</p>
|
|
3770
|
-
<hr />
|
|
3771
|
-
<h2 id="b.8-practical-implementation"><strong>B.8 Practical
|
|
3772
|
-
implementation</strong></h2>
|
|
3773
|
-
<p>In a Python prototype:</p>
|
|
3774
|
-
<div class="sourceCode" id="cb137"><pre
|
|
3775
|
-
class="sourceCode python"><code class="sourceCode python"><span id="cb137-1"><a href="#cb137-1" aria-hidden="true" tabindex="-1"></a>EXTERNAL_TYPES <span class="op">=</span> {</span>
|
|
3776
|
-
<span id="cb137-2"><a href="#cb137-2" aria-hidden="true" tabindex="-1"></a> <span class="st">"$int"</span>: {<span class="st">"hash"</span>: <span class="st">"E001"</span>, <span class="st">"kind"</span>: <span class="st">"external"</span>, <span class="st">"runtime_kind"</span>: <span class="st">"primitive_i64"</span>}</span>
|
|
3777
|
-
<span id="cb137-3"><a href="#cb137-3" aria-hidden="true" tabindex="-1"></a>}</span>
|
|
3778
|
-
<span id="cb137-4"><a href="#cb137-4" aria-hidden="true" tabindex="-1"></a></span>
|
|
3779
|
-
<span id="cb137-5"><a href="#cb137-5" aria-hidden="true" tabindex="-1"></a>EXTERNAL_FUNCS <span class="op">=</span> {</span>
|
|
3780
|
-
<span id="cb137-6"><a href="#cb137-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"add"</span>: {<span class="st">"inputs"</span>: [<span class="st">"$int"</span>, <span class="st">"$int"</span>], <span class="st">"output"</span>: <span class="st">"$int"</span>, <span class="st">"symbol"</span>: <span class="st">"k_ext_add"</span>},</span>
|
|
3781
|
-
<span id="cb137-7"><a href="#cb137-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"less"</span>: {<span class="st">"inputs"</span>: [<span class="st">"$int"</span>, <span class="st">"$int"</span>], <span class="st">"output"</span>: <span class="st">"$bool"</span>, <span class="st">"symbol"</span>: <span class="st">"k_ext_less"</span>}</span>
|
|
3782
|
-
<span id="cb137-8"><a href="#cb137-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
|
3783
|
-
<p>During code generation, when a call refers to an external function,
|
|
3784
|
-
the compiler emits a call to the symbol given in the table.</p>
|
|
3785
|
-
<hr />
|
|
3786
|
-
<h2 id="b.9-summary"><strong>B.9 Summary</strong></h2>
|
|
3787
|
-
<ul>
|
|
3788
|
-
<li>External predefined types extend k without altering its core
|
|
3789
|
-
semantics.</li>
|
|
3790
|
-
<li>They are registered with hashes and treated as atomic nodes.</li>
|
|
3791
|
-
<li>External functions follow the same calling convention as normal
|
|
3792
|
-
ones.</li>
|
|
3793
|
-
<li>Serialization of external values uses type-specific codecs.</li>
|
|
3794
|
-
<li>This mechanism allows integration of native computations (numbers,
|
|
3795
|
-
strings, system data) while preserving the purity and determinism of the
|
|
3796
|
-
k language.</li>
|
|
3797
|
-
</ul>
|
|
3798
|
-
<hr />
|