v / vlib / v2 / ssa / build_fn_bodies_from_flat_test.v
112 lines · 100 sloc · 3.32 KB · 164b30309e6337b95ec2baacacd0f101fafd3d97
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// vtest build: macos
5//
6// Bit-equality pin for s174: `build_fn_bodies_from_flat` (flat-cursor port)
7// must build the same SSA bodies as the legacy `build_fn_bodies`. The flat
8// port walks one file's top-level stmts via FileCursor and reads FnDecl
9// signatures, filters, params, and body statements directly from cursors.
10// Non-FnDecl stmts (ModuleStmt, StructDecl, EnumDecl, ConstDecl, etc.) are
11// never decoded.
12module ssa
13
14import v2.ast
15import v2.types
16
17fn make_build_fn_bodies_fixture() []ast.File {
18 return [
19 ast.File{
20 name: 'main.v'
21 mod: 'main'
22 stmts: [
23 ast.Stmt(ast.ModuleStmt{
24 name: 'main'
25 }),
26 ast.Stmt(ast.FnDecl{
27 name: 'answer'
28 typ: ast.FnType{
29 return_type: ast.Expr(ast.Ident{
30 name: 'int'
31 })
32 }
33 stmts: [
34 ast.Stmt(ast.ReturnStmt{
35 exprs: [
36 ast.Expr(ast.BasicLiteral{
37 kind: .number
38 value: '42'
39 }),
40 ]
41 }),
42 ]
43 }),
44 ast.Stmt(ast.FnDecl{
45 name: 'noop'
46 typ: ast.FnType{}
47 }),
48 ]
49 },
50 ]
51}
52
53// build_fn_bodies_from_flat on a file with no fns must not build any
54// function bodies — same as build_fn_bodies.
55fn test_build_fn_bodies_from_flat_no_fns_matches_legacy() {
56 files := [
57 ast.File{
58 name: 'empty.v'
59 mod: 'main'
60 stmts: [ast.Stmt(ast.ModuleStmt{
61 name: 'main'
62 })]
63 },
64 ]
65 flat := ast.flatten_files(files)
66
67 env := types.Environment.new()
68
69 mut mod_legacy := Module.new('bfb_empty_legacy')
70 mut b_legacy := Builder.new_with_env(mod_legacy, env)
71 b_legacy.build_fn_bodies(files[0])
72
73 mut mod_flat := Module.new('bfb_empty_flat')
74 mut b_flat := Builder.new_with_env(mod_flat, env)
75 b_flat.build_fn_bodies_from_flat(flat.file_cursor(0))
76
77 // Neither path built any function bodies.
78 assert mod_legacy.funcs.len == mod_flat.funcs.len
79 assert mod_legacy.blocks.len == mod_flat.blocks.len
80 assert mod_legacy.instrs.len == mod_flat.instrs.len
81}
82
83// build_fn_bodies_from_flat on a file with two FnDecls (answer + noop) must
84// build identical SSA bodies — same number of funcs, blocks, and instrs.
85fn test_build_fn_bodies_from_flat_matches_legacy_for_two_fns() {
86 files := make_build_fn_bodies_fixture()
87 flat := ast.flatten_files(files)
88
89 env := types.Environment.new()
90
91 mut mod_legacy := Module.new('bfb_two_legacy')
92 mut b_legacy := Builder.new_with_env(mod_legacy, env)
93 // build_fn requires fn_index populated (register_fn_signatures runs in
94 // Phase 3 before Phase 4 in legacy build_all).
95 b_legacy.register_fn_signatures(files[0])
96 b_legacy.build_fn_bodies(files[0])
97
98 mut mod_flat := Module.new('bfb_two_flat')
99 mut b_flat := Builder.new_with_env(mod_flat, env)
100 b_flat.register_fn_signatures_from_flat(flat.file_cursor(0))
101 b_flat.build_fn_bodies_from_flat(flat.file_cursor(0))
102
103 // Both paths registered + built 2 fns.
104 assert mod_legacy.funcs.len == mod_flat.funcs.len
105 assert mod_legacy.funcs.len == 2
106 // Same number of basic blocks on both paths (identical control flow).
107 assert mod_legacy.blocks.len == mod_flat.blocks.len
108 // Same number of instructions emitted (return 42 + return void).
109 assert mod_legacy.instrs.len == mod_flat.instrs.len
110 // Same number of SSA values.
111 assert mod_legacy.values.len == mod_flat.values.len
112}
113