Skip to content

Commit 057970b

Browse files
committed
v2: parallel transformer (x2 sped up)
1 parent 5c773f5 commit 057970b

9 files changed

Lines changed: 486 additions & 30 deletions

File tree

vlib/v3/flat/flat.v

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,24 @@ pub fn (mut a FlatAst) add_val_id(kind_id int, value string) NodeId {
220220
return id
221221
}
222222

223+
// with_shifted_children returns a copy of the node whose children_start is moved
224+
// by `shift`. children_start lives in the immutable section of Node, so callers
225+
// that relocate a node's children block (e.g. the parallel-transform merge) build
226+
// a fresh node instead of mutating in place.
227+
pub fn (n Node) with_shifted_children(shift i32) Node {
228+
return Node{
229+
value: n.value
230+
typ: n.typ
231+
generic_params: n.generic_params
232+
kind_id: n.kind_id
233+
pos: n.pos
234+
children_start: n.children_start + shift
235+
children_count: n.children_count
236+
kind: n.kind
237+
op: n.op
238+
}
239+
}
240+
223241
// add_node updates add node state for FlatAst.
224242
pub fn (mut a FlatAst) add_node(node Node) NodeId {
225243
id := NodeId(a.nodes.len)

vlib/v3/gen/c/cleanc.v

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ mut:
6363
array_method_cache map[string]string
6464
param_types_cache map[string][]types.Type // (name|fallback) -> resolved param types
6565
embedded_fields_by_type map[string][]types.StructField // type name -> its embedded fields (usually empty)
66+
param_types_by_short map[string][]types.Type // method short-name suffix -> param types (fallback index)
6667
spawn_wrapper_names map[string]string
6768
spawn_wrapper_defs []string
6869
parallel_used bool
@@ -119,6 +120,7 @@ pub fn FlatGen.new() FlatGen {
119120
array_method_cache: map[string]string{}
120121
param_types_cache: map[string][]types.Type{}
121122
embedded_fields_by_type: map[string][]types.StructField{}
123+
param_types_by_short: map[string][]types.Type{}
122124
spawn_wrapper_names: map[string]string{}
123125
spawn_wrapper_defs: []string{}
124126
str_lits: []string{}
@@ -189,6 +191,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
189191
g.array_method_cache = map[string]string{}
190192
g.param_types_cache = map[string][]types.Type{}
191193
g.embedded_fields_by_type = map[string][]types.StructField{}
194+
g.param_types_by_short = map[string][]types.Type{}
192195
g.spawn_wrapper_names = map[string]string{}
193196
g.spawn_wrapper_defs = []string{}
194197
g.parallel_used = false
@@ -199,6 +202,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
199202
g.has_builtins = g.tc.has_builtins
200203
g.collect_gen_info()
201204
g.precompute_embedded_fields()
205+
g.precompute_param_type_index()
202206
g.collect_interface_impls()
203207
g.preseed_struct_fn_ptr_types()
204208
g.preseed_global_fn_ptr_types()
@@ -215,6 +219,9 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
215219
g.enum_decls()
216220
g.type_alias_decls()
217221
g.type_forward_decls()
222+
// Forward-declare multi-return structs before fn-ptr typedefs, which may name a
223+
// multi-return as a by-value return type (full bodies come after struct_decls).
224+
g.multi_return_forward_decls()
218225
g.fn_ptr_typedefs()
219226
g.struct_decls()
220227
g.fixed_array_typedefs()

vlib/v3/gen/c/fn.v

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,22 +2044,36 @@ fn (mut g FlatGen) param_types_for_uncached(name string, fallback string) []type
20442044
return decl_types
20452045
}
20462046
if name.contains('.') {
2047+
// O(1) lookup via the precomputed short-name index instead of scanning the whole
2048+
// function table on every (cache-missing) call — this fallback ran ~3000× and was
2049+
// a top cgen self-time cost (each scan is O(functions)).
20472050
short_name := name.all_after_last('.')
2048-
suffix := '.${short_name}'
2049-
// Look up the value only on a match: `for _, v in map` copies every array value
2050-
// on every iteration, which is wasteful for a table-wide scan.
2051-
for candidate, _ in g.fn_decl_param_types {
2052-
if candidate.ends_with(suffix) {
2053-
return g.fn_decl_param_types[candidate]
2051+
if params := g.param_types_by_short[short_name] {
2052+
return params
2053+
}
2054+
}
2055+
return []types.Type{}
2056+
}
2057+
2058+
// precompute_param_type_index builds short-name -> param-types, preserving the fallback's
2059+
// priority (fn_decl_param_types first, then the checker's fn_param_types; first match wins).
2060+
fn (mut g FlatGen) precompute_param_type_index() {
2061+
for name, params in g.fn_decl_param_types {
2062+
if name.contains('.') {
2063+
short := name.all_after_last('.')
2064+
if short !in g.param_types_by_short {
2065+
g.param_types_by_short[short] = params
20542066
}
20552067
}
2056-
for candidate, _ in g.tc.fn_param_types {
2057-
if candidate.ends_with(suffix) {
2058-
return g.tc.fn_param_types[candidate]
2068+
}
2069+
for name, params in g.tc.fn_param_types {
2070+
if name.contains('.') {
2071+
short := name.all_after_last('.')
2072+
if short !in g.param_types_by_short {
2073+
g.param_types_by_short[short] = params
20592074
}
20602075
}
20612076
}
2062-
return []types.Type{}
20632077
}
20642078

20652079
fn (g &FlatGen) interface_method_param_types(name string) ?[]types.Type {
@@ -3051,11 +3065,46 @@ fn fn_ptr_typedef_is_generic_placeholder(typ string) bool {
30513065
return short.len == 1 && short[0] >= `A` && short[0] <= `Z`
30523066
}
30533067

3054-
// multi_return_typedefs supports multi return typedefs handling for FlatGen.
3068+
// multi_return_forward_decls forward-declares every multi-return struct that the
3069+
// generated C can reference by name. It must run before fn_ptr_typedefs(), because
3070+
// a function-pointer typedef may name a multi-return as its (by-value) return type
3071+
// — and a `typedef RET (*fp)(...)` only needs RET's tag declared, not its full
3072+
// layout. The full struct bodies are emitted later by multi_return_typedefs(),
3073+
// after the member struct definitions they depend on are available.
3074+
fn (mut g FlatGen) multi_return_forward_decls() {
3075+
mut emitted := map[string]bool{}
3076+
g.walk_multi_return_typedefs(mut emitted, true)
3077+
// Also cover multi-returns reachable only as a fn-pointer return type: parallel
3078+
// cgen preseeds fn-ptr types that the serial path never materializes, so their
3079+
// return multi-returns may not appear among the function/expression types above.
3080+
for encoded, _ in g.fn_ptr_types {
3081+
ret, _ := fn_ptr_typedef_parts(encoded)
3082+
if ret.starts_with('multi_return_') && ret !in emitted {
3083+
emitted[ret] = true
3084+
g.writeln('typedef struct ${ret} ${ret};')
3085+
}
3086+
}
3087+
if emitted.len > 0 {
3088+
g.writeln('')
3089+
}
3090+
}
3091+
3092+
// multi_return_typedefs emits the full struct definitions for multi-return types.
30553093
fn (mut g FlatGen) multi_return_typedefs() {
30563094
mut emitted := map[string]bool{}
3095+
g.walk_multi_return_typedefs(mut emitted, false)
3096+
if emitted.len > 0 {
3097+
g.writeln('')
3098+
}
3099+
}
3100+
3101+
// walk_multi_return_typedefs visits every multi-return type reachable from a
3102+
// function return type or an expression type and emits it via emit_multi_return_typedef.
3103+
// Shared by the forward-declaration and full-definition passes so both see the same
3104+
// set in the same (deterministic) order.
3105+
fn (mut g FlatGen) walk_multi_return_typedefs(mut emitted map[string]bool, forward_only bool) {
30573106
for _, ret in g.tc.fn_ret_types {
3058-
g.emit_multi_return_typedef(ret, mut emitted)
3107+
g.emit_multi_return_typedef(ret, mut emitted, forward_only)
30593108
}
30603109
mut cur_module := ''
30613110
mut cur_file := ''
@@ -3076,23 +3125,28 @@ fn (mut g FlatGen) multi_return_typedefs() {
30763125
}
30773126
g.tc.cur_file = cur_file
30783127
g.tc.cur_module = cur_module
3079-
if node.typ.len > 0 {
3080-
g.emit_multi_return_typedef(g.tc.parse_type(node.typ), mut emitted)
3128+
// emit_multi_return_typedef only acts on (optionally `?`/`!`-wrapped) multi-return
3129+
// types, whose string form always begins with `(`. Skip parse_type for everything
3130+
// else — this ran on every node's type (~hundreds of thousands of parse_type calls).
3131+
typ := node.typ
3132+
if typ.len > 0 && (typ[0] == `(` || ((typ[0] == `?` || typ[0] == `!`) && typ.len > 1
3133+
&& typ[1] == `(`)) {
3134+
g.emit_multi_return_typedef(g.tc.parse_type(typ), mut emitted, forward_only)
30813135
}
30823136
}
3083-
if emitted.len > 0 {
3084-
g.writeln('')
3085-
}
30863137
}
30873138

3088-
// emit_multi_return_typedef emits emit multi return typedef output for c.
3089-
fn (mut g FlatGen) emit_multi_return_typedef(ret types.Type, mut emitted map[string]bool) {
3139+
// emit_multi_return_typedef emits one multi-return type: a forward declaration
3140+
// (`typedef struct NAME NAME;`) when forward_only, otherwise the full struct body
3141+
// (`struct NAME { ... };`). The two forms are paired — the forward decl provides the
3142+
// typedef name, the body completes the tagged struct.
3143+
fn (mut g FlatGen) emit_multi_return_typedef(ret types.Type, mut emitted map[string]bool, forward_only bool) {
30903144
if ret is types.OptionType {
3091-
g.emit_multi_return_typedef(ret.base_type, mut emitted)
3145+
g.emit_multi_return_typedef(ret.base_type, mut emitted, forward_only)
30923146
return
30933147
}
30943148
if ret is types.ResultType {
3095-
g.emit_multi_return_typedef(ret.base_type, mut emitted)
3149+
g.emit_multi_return_typedef(ret.base_type, mut emitted, forward_only)
30963150
return
30973151
}
30983152
if ret is types.MultiReturn {
@@ -3101,11 +3155,15 @@ fn (mut g FlatGen) emit_multi_return_typedef(ret types.Type, mut emitted map[str
31013155
return
31023156
}
31033157
emitted[name] = true
3104-
g.writeln('typedef struct {')
3105-
for i, typ in ret.types {
3106-
g.writeln('\t${g.tc.c_type(typ)} arg${i};')
3158+
if forward_only {
3159+
g.writeln('typedef struct ${name} ${name};')
3160+
} else {
3161+
g.writeln('struct ${name} {')
3162+
for i, typ in ret.types {
3163+
g.writeln('\t${g.tc.c_type(typ)} arg${i};')
3164+
}
3165+
g.writeln('};')
31073166
}
3108-
g.writeln('} ${name};')
31093167
}
31103168
}
31113169

vlib/v3/gen/c/fn_d_parallel.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ fn (g &FlatGen) new_parallel_worker(worker_id int) &FlatGen {
373373
array_method_cache: g.array_method_cache.clone()
374374
param_types_cache: g.param_types_cache.clone()
375375
embedded_fields_by_type: g.embedded_fields_by_type.clone()
376+
param_types_by_short: g.param_types_by_short.clone()
376377
}
377378
}
378379

0 commit comments

Comments
 (0)