Skip to content

Commit 71e0097

Browse files
committed
v3: fixes to compile v1 compiler
1 parent 8687a93 commit 71e0097

37 files changed

Lines changed: 14014 additions & 1499 deletions

vlib/v3/README.md

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,19 @@ match-based smartcasting are all supported. The transformer lowers sum type
3939
match branches to `is_expr` nodes, enabling smartcast field access through union
4040
variants in both `if` and `match` blocks.
4141

42-
Type checking runs as a shared pipeline phase before backend selection:
42+
Type checking runs before transform, matching V1 and V2:
4343
`TypeChecker.collect()` walks the flat AST to extract function signatures,
4444
struct fields, enum names, type aliases, sum types, and C function declarations,
45-
then registers runtime method signatures. Both the C backend and future backends
46-
receive the pre-populated `TypeChecker`.
45+
then registers runtime method signatures. `check_semantics()` validates the
46+
unlowered source program before the transformer rewrites it. Both the C backend
47+
and future backends receive the pre-populated `TypeChecker`.
48+
49+
After transform, v3 runs `annotate_types()`. This is not a second semantic
50+
checker pass and should not report source diagnostics. It repopulates
51+
expression-type metadata for the post-transform flat AST, including new node IDs
52+
created by lowering. V1 and V2 do not need a separate step because their checker
53+
updates the typed AST/table that later stages keep using directly; v3's flat AST
54+
keeps those per-node caches outside the nodes.
4755

4856
Imports are resolved recursively: after parsing the input file, the driver
4957
collects `import_decl` nodes, resolves module paths, parses module files, and
@@ -53,9 +61,9 @@ repeats until no new imports are found.
5361

5462
```
5563
source + vlib/builtin -> scanner -> flat parser -> flat AST -> imports
56-
-> transform -> check -> markused -> gen C -> cc
57-
\-> SSA build -> ARM64 gen -> link
58-
\-> optimize -> MIR -> insel (-prod)
64+
-> check -> transform -> annotate types -> markused -> gen C -> cc
65+
\-> SSA build -> ARM64 gen -> link
66+
\-> optimize -> MIR -> insel (-prod)
5967
```
6068

6169
The parser directly emits a flat AST. There is no recursive AST intermediate and
@@ -93,7 +101,8 @@ lowers to C type strings only at final emission. Lexical scopes store
93101
generation. Function bodies from builtins are skipped during C code generation;
94102
only type and declaration information is used.
95103

96-
The transformer lowers match statements to if/else chains and collects struct/global type info.
104+
The transformer lowers match statements to if/else chains and collects
105+
struct/global type info for its own type-dependent rewrites.
97106

98107
The markused pass performs reachability analysis from `main`, building a call
99108
graph and BFS-walking to find all used functions. Method calls are resolved to
@@ -172,36 +181,37 @@ function pointers.
172181
| cc | 79 ms | 17,312 KB |
173182
| **total** | **~259 ms** | **17,312 KB** |
174183

175-
All v3 steps (parse + transform + check + markused + gen + write) complete in
176-
~8 ms for hello world, including 38 builtin files, and ~157 ms for `test.v`
177-
with the C backend.
184+
All v3 steps (parse + check + transform + annotate types + markused + gen +
185+
write) complete in ~8 ms for hello world, including 38 builtin files, and
186+
~157 ms for `test.v` with the C backend.
178187

179188
Peak RSS: 9-17 MB.
180189

181-
Compiling `v3.v` itself with a `v3` seed binary built by V:
190+
Compiling `v3.v` itself in the C self-host chain:
182191

183192
Commands:
184193

185-
- `./vnew -o /tmp/v3_perf_seed vlib/v3`
186-
- `/tmp/v3_perf_seed vlib/v3/v3.v -o /tmp/v3_self_c_perf_warm`
187-
- `/tmp/v3_perf_seed vlib/v3/v3.v -b arm64 -o /tmp/v3_self_arm_perf_warm`
188-
189-
Both backend rows compile the target without `-prod`. The C backend uses
190-
bundled TCC for the final `cc` step; the ARM64 backend emits and links a
191-
Mach-O binary directly.
192-
193-
| Phase | C backend | ARM64 backend |
194-
|-------------|----------:|--------------:|
195-
| parse | 69 ms | 71 ms |
196-
| transform | 489 ms | 486 ms |
197-
| check | 176 ms | 171 ms |
198-
| markused | 356 ms | 354 ms |
199-
| gen C/write | 345 ms | - |
200-
| ssa build | - | 3,931 ms |
201-
| arm64 gen | - | 1,414 ms |
202-
| cc/link | 56 ms | 226 ms |
203-
| **total** | **1,509 ms** | **6,677 ms** |
204-
| Peak RSS | 171 MB | 399 MB |
194+
```sh
195+
v -gc none -prod -o v3 v3.v
196+
./v3 -parallel -o v4 v3.v
197+
./v4 -o v5 v3.v
198+
./v5 -o v6 v3.v
199+
```
200+
201+
The table uses the first v3-generated C stage, `./v3 -parallel -o v4 v3.v`.
202+
Bundled TCC currently rejects the atomic helper shims on macOS and the driver
203+
falls back to `cc`.
204+
205+
| Phase | Time | Peak RSS |
206+
|----------------|----------:|---------:|
207+
| parse | 47.33 ms | 73 MB |
208+
| check | 43.92 ms | 131 MB |
209+
| transform | 94.83 ms | 274 MB |
210+
| annotate types | 30.46 ms | 307 MB |
211+
| markused | 48.53 ms | 354 MB |
212+
| gen C/write | 94.67 ms | 455 MB |
213+
| cc | 707.84 ms | 455 MB |
214+
| **total** | **1,092.92 ms** | **455 MB** |
205215

206216
## Comparison with V1
207217

vlib/v3/flat/flat.v

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub const empty_node = NodeId(-1)
88

99
const empty_node_value = Node{}
1010

11-
pub enum NodeKind as u8 {
11+
pub enum NodeKind {
1212
empty
1313
// expressions
1414
int_literal
@@ -93,7 +93,7 @@ pub enum NodeKind as u8 {
9393
file
9494
}
9595

96-
pub enum Op as u8 {
96+
pub enum Op {
9797
none
9898
plus
9999
minus
@@ -111,6 +111,7 @@ pub enum Op as u8 {
111111
xor
112112
left_shift
113113
right_shift
114+
right_shift_unsigned
114115
logical_and
115116
logical_or
116117
not
@@ -126,6 +127,7 @@ pub enum Op as u8 {
126127
xor_assign
127128
left_shift_assign
128129
right_shift_assign
130+
right_shift_unsigned_assign
129131
inc
130132
dec
131133
dot
@@ -134,8 +136,9 @@ pub enum Op as u8 {
134136

135137
pub struct Node {
136138
pub mut:
137-
value string
138-
typ string
139+
value string
140+
typ string
141+
kind_id int
139142
pub:
140143
pos token.Pos
141144
children_start i32
@@ -162,23 +165,53 @@ pub fn FlatAst.new() FlatAst {
162165
pub fn (mut a FlatAst) add(kind NodeKind) NodeId {
163166
id := NodeId(a.nodes.len)
164167
a.nodes << Node{
165-
kind: kind
168+
kind: kind
169+
kind_id: int(kind)
166170
}
167171
return id
168172
}
169173

174+
pub fn (mut a FlatAst) add_id(kind_id int) NodeId {
175+
id := NodeId(a.nodes.len)
176+
a.nodes << Node{
177+
kind: node_kind_from_id(kind_id)
178+
kind_id: kind_id
179+
}
180+
return id
181+
}
182+
183+
@[inline]
184+
pub fn node_kind_from_id(id int) NodeKind {
185+
return unsafe { NodeKind(id) }
186+
}
187+
170188
pub fn (mut a FlatAst) add_val(kind NodeKind, value string) NodeId {
171189
id := NodeId(a.nodes.len)
172190
a.nodes << Node{
173-
kind: kind
174-
value: value
191+
kind: kind
192+
kind_id: int(kind)
193+
value: value
194+
}
195+
return id
196+
}
197+
198+
pub fn (mut a FlatAst) add_val_id(kind_id int, value string) NodeId {
199+
id := NodeId(a.nodes.len)
200+
a.nodes << Node{
201+
kind: node_kind_from_id(kind_id)
202+
kind_id: kind_id
203+
value: value
175204
}
176205
return id
177206
}
178207

179208
pub fn (mut a FlatAst) add_node(node Node) NodeId {
180209
id := NodeId(a.nodes.len)
181-
a.nodes << node
210+
mut n := node
211+
if n.kind_id == 0 && int(n.kind) != 0 {
212+
n.kind_id = int(n.kind)
213+
}
214+
a.nodes << n
182215
return id
183216
}
184217

0 commit comments

Comments
 (0)