v / vlib / v2 / ssa / build_prefix_from_flat_test.v
125 lines · 119 sloc · 3.58 KB · d358576851079d4716834cc86627307d28acd1ae
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 s190: `build_prefix_from_flat` is the sixth per-kind
7// arm inside `build_expr_from_flat`. Reads `op` from `c.aux()` and decodes
8// the operand from edge 0. The inner decode is required because
9// build_prefix pattern-matches on the operand via several `is` type checks
10// (CastExpr / CallOrCastExpr / PrefixExpr / InitExpr).
11module ssa
12
13import v2.ast
14import v2.token
15import v2.types
16
17// Fixture: `fn neg(x int) int { return -x }`. PrefixExpr with op=.minus
18// around an Ident. Exercises the common-case path in build_prefix
19// (none of the special-case pattern matches fire).
20fn make_prefix_fixture() []ast.File {
21 return [
22 ast.File{
23 name: 'main.v'
24 mod: 'main'
25 stmts: [
26 ast.Stmt(ast.ModuleStmt{
27 name: 'main'
28 }),
29 ast.Stmt(ast.FnDecl{
30 name: 'neg'
31 typ: ast.FnType{
32 params: [
33 ast.Parameter{
34 name: 'x'
35 typ: ast.Expr(ast.Ident{
36 name: 'int'
37 })
38 },
39 ]
40 return_type: ast.Expr(ast.Ident{
41 name: 'int'
42 })
43 }
44 stmts: [
45 ast.Stmt(ast.ReturnStmt{
46 exprs: [
47 ast.Expr(ast.PrefixExpr{
48 op: token.Token.minus
49 expr: ast.Expr(ast.Ident{
50 name: 'x'
51 })
52 }),
53 ]
54 }),
55 ]
56 }),
57 ]
58 },
59 ]
60}
61
62fn build_via_legacy_prefix(files []ast.File, env &types.Environment, name string) &Module {
63 mut mod := Module.new(name)
64 mut b := Builder.new_with_env(mod, env)
65 b.register_fn_signatures(files[0])
66 b.build_fn_bodies(files[0])
67 return mod
68}
69
70fn build_via_flat_prefix(files []ast.File, env &types.Environment, name string) &Module {
71 flat := ast.flatten_files(files)
72 mut mod := Module.new(name)
73 mut b := Builder.new_with_env(mod, env)
74 b.register_fn_signatures_from_flat(flat.file_cursor(0))
75 stmts := flat.file_cursor(0).stmts()
76 for si in 0 .. stmts.len() {
77 c := stmts.at(si)
78 if c.kind() != .stmt_fn_decl {
79 continue
80 }
81 decl := c.fn_decl_signature()
82 fn_name := b.mangle_fn_name(decl)
83 func_idx := b.fn_index[fn_name] or { continue }
84 b.cur_func = func_idx
85 b.label_blocks = map[string]BlockID{}
86 b.vars = map[string]ValueID{}
87 entry := mod.add_block(func_idx, 'entry')
88 b.cur_block = entry
89 for param in decl.typ.params {
90 param_type := b.ast_type_to_ssa(param.typ)
91 param_val := mod.add_value_node(.argument, param_type, param.name, 0)
92 mod.func_add_param(func_idx, param_val)
93 alloca := mod.add_instr(.alloca, entry, mod.type_store.get_ptr(param_type), []ValueID{})
94 mod.add_instr(.store, entry, 0, [param_val, alloca])
95 b.vars[param.name] = alloca
96 }
97 body := c.list_at(3)
98 for bi in 0 .. body.len() {
99 stmt_c := body.at(bi)
100 if stmt_c.kind() == .stmt_return {
101 ret_expr_c := stmt_c.edge(0)
102 val := b.build_expr_from_flat(ret_expr_c)
103 mod.add_instr(.ret, b.cur_block, 0, [val])
104 } else {
105 b.build_stmt_from_flat(stmt_c)
106 }
107 }
108 if !b.block_has_terminator(b.cur_block) {
109 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
110 }
111 }
112 return mod
113}
114
115fn test_build_prefix_from_flat_neg_matches_legacy() {
116 files := make_prefix_fixture()
117 env := types.Environment.new()
118 mod_legacy := build_via_legacy_prefix(files, env, 'prefix_legacy')
119 mod_flat := build_via_flat_prefix(files, env, 'prefix_flat')
120
121 assert mod_legacy.funcs.len == mod_flat.funcs.len
122 assert mod_legacy.blocks.len == mod_flat.blocks.len
123 assert mod_legacy.instrs.len == mod_flat.instrs.len
124 assert mod_legacy.values.len == mod_flat.values.len
125}
126