v4 / vlib / v3 / tests / parallel_cgen_test.v
288 lines · 265 sloc · 10.35 KB · 43cc1a753b87c28c065b21ea1521fe45ba36cdf0
Raw
1import os
2import strings
3
4const parallel_tests_dir = os.dir(@FILE)
5const parallel_v3_dir = os.dir(parallel_tests_dir)
6const parallel_vlib_dir = os.dir(parallel_v3_dir)
7const parallel_v3_src = os.join_path(parallel_v3_dir, 'v3.v')
8
9// build_parallel_v3 builds parallel v3 data for v3 tests.
10fn build_parallel_v3() string {
11 vexe := @VEXE
12 v3_bin := os.join_path(os.temp_dir(), 'v3_parallel_cgen_test')
13 os.rm(v3_bin) or {}
14 build :=
15 os.execute('${vexe} -d parallel -gc none -path "${parallel_vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${parallel_v3_src}')
16 assert build.exit_code == 0, build.output
17 return v3_bin
18}
19
20fn build_parallel_prod_v3() string {
21 vexe := @VEXE
22 v3_bin := os.join_path(os.temp_dir(), 'v3_parallel_prod_cgen_test_${os.getpid()}')
23 os.rm(v3_bin) or {}
24 build :=
25 os.execute('${vexe} -d parallel -gc none -prod -path "${parallel_vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${parallel_v3_src}')
26 assert build.exit_code == 0, build.output
27 return v3_bin
28}
29
30// write_parallel_module_init_project writes parallel module init project output for v3 tests.
31fn write_parallel_module_init_project(name string) string {
32 project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
33 os.rmdir_all(project_dir) or {}
34 os.mkdir_all(os.join_path(project_dir, 'moda')) or { panic(err) }
35
36 mut main_src := strings.new_builder(64_000)
37 main_src.writeln('module main')
38 main_src.writeln('')
39 main_src.writeln('import moda')
40 main_src.writeln('')
41 for i in 0 .. 1050 {
42 main_src.writeln('fn helper_${i}() int {')
43 main_src.writeln('\treturn ${i}')
44 main_src.writeln('}')
45 main_src.writeln('')
46 }
47 main_src.writeln('fn main() {')
48 main_src.writeln('\tmut total := 0')
49 for i in 0 .. 1050 {
50 main_src.writeln('\ttotal += helper_${i}()')
51 }
52 main_src.writeln('\tprintln(int_str(total + moda.value()))')
53 main_src.writeln('}')
54 os.write_file(os.join_path(project_dir, 'main.v'), main_src.str()) or { panic(err) }
55
56 os.write_file(os.join_path(project_dir, 'moda', 'moda.v'), 'module moda
57
58__global x int
59
60fn init() {
61 x = 7
62}
63
64pub fn value() int {
65 return x
66}
67') or {
68 panic(err)
69 }
70 return os.join_path(project_dir, 'main.v')
71}
72
73// test_parallel_cgen_main_emits_module_init_call validates this v3 regression case.
74fn test_parallel_cgen_main_emits_module_init_call() {
75 v3_bin := build_parallel_v3()
76 main_path := write_parallel_module_init_project('parallel_module_init')
77 c_out := os.join_path(os.temp_dir(), 'v3_parallel_module_init.c')
78 compile := os.execute('VJOBS=2 ${v3_bin} ${main_path} -o ${c_out}')
79 assert compile.exit_code == 0, compile.output
80 assert compile.output.contains('cgen'), compile.output
81 c_code := os.read_file(c_out) or { panic(err) }
82 assert c_code.all_after('int main').contains('_vinit();')
83}
84
85fn write_parallel_gettid_project(name string) string {
86 project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
87 os.rmdir_all(project_dir) or {}
88 os.mkdir_all(project_dir) or { panic(err) }
89
90 mut main_src := strings.new_builder(96_000)
91 main_src.writeln('module main')
92 main_src.writeln('')
93 main_src.writeln('fn C.gettid() int')
94 main_src.writeln('')
95 for i in 0 .. 1050 {
96 main_src.writeln('fn helper_${i}() int {')
97 main_src.writeln('\treturn ${i}')
98 main_src.writeln('}')
99 main_src.writeln('')
100 }
101 main_src.writeln('fn worker_gettid_value() int {')
102 main_src.writeln('\treturn C.gettid()')
103 main_src.writeln('}')
104 main_src.writeln('')
105 main_src.writeln('fn main() {')
106 main_src.writeln('\tmut total := 0')
107 for i in 0 .. 1050 {
108 main_src.writeln('\ttotal += helper_${i}()')
109 }
110 main_src.writeln('\tprintln(int_str(total + worker_gettid_value()))')
111 main_src.writeln('}')
112 os.write_file(os.join_path(project_dir, 'main.v'), main_src.str()) or { panic(err) }
113 return os.join_path(project_dir, 'main.v')
114}
115
116fn test_parallel_cgen_merges_worker_gettid_compat() {
117 v3_bin := build_parallel_v3()
118 main_path := write_parallel_gettid_project('parallel_gettid_compat')
119 c_out := os.join_path(os.temp_dir(), 'v3_parallel_gettid_compat.c')
120 compile := os.execute('VJOBS=2 ${v3_bin} ${main_path} -o ${c_out}')
121 assert compile.exit_code == 0, compile.output
122 assert compile.output.contains('cgen'), compile.output
123 c_code := os.read_file(c_out) or { panic(err) }
124 assert c_code.contains('static inline u32 v3_gettid(void)'), c_code
125 assert c_code.contains('return v3_gettid();'), c_code
126}
127
128fn write_parallel_user_main_test_project(name string) string {
129 project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
130 os.rmdir_all(project_dir) or {}
131 os.mkdir_all(project_dir) or { panic(err) }
132
133 mut main_src := strings.new_builder(96_000)
134 main_src.writeln('module main')
135 main_src.writeln('')
136 for i in 0 .. 1050 {
137 main_src.writeln('fn helper_${i}() int {')
138 main_src.writeln('\treturn ${i}')
139 main_src.writeln('}')
140 main_src.writeln('')
141 }
142 main_src.writeln('fn main() {')
143 main_src.writeln("\tprintln('user-main')")
144 main_src.writeln('}')
145 main_src.writeln('')
146 main_src.writeln('fn test_call_user_main() {')
147 main_src.writeln('\tmut total := 0')
148 for i in 0 .. 1050 {
149 main_src.writeln('\ttotal += helper_${i}()')
150 }
151 main_src.writeln('\tassert total == 550725')
152 main_src.writeln('\tmain()')
153 main_src.writeln('}')
154 os.write_file(os.join_path(project_dir, 'main_test.v'), main_src.str()) or { panic(err) }
155 return os.join_path(project_dir, 'main_test.v')
156}
157
158fn test_parallel_cgen_worker_keeps_test_user_main_renamed() {
159 v3_bin := build_parallel_v3()
160 main_path := write_parallel_user_main_test_project('parallel_user_main_test_file')
161 bin_out := os.join_path(os.temp_dir(), 'v3_parallel_user_main_test_file_out')
162 compile := os.execute('VJOBS=2 ${v3_bin} ${main_path} -b c -o ${bin_out}')
163 assert compile.exit_code == 0, compile.output
164 assert compile.output.contains('cgen'), compile.output
165 run := os.execute(bin_out)
166 assert run.exit_code == 0, run.output
167 assert run.output.trim_space() == 'user-main'
168 c_code := os.read_file(bin_out + '.c') or { panic(err) }
169 assert c_code.count('int main(') == 1, c_code
170 assert c_code.contains('main__user_main'), c_code
171 assert c_code.contains('main__user_main();'), c_code
172}
173
174fn write_parallel_generic_struct_method_project(name string) string {
175 project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
176 os.rmdir_all(project_dir) or {}
177 os.mkdir_all(project_dir) or { panic(err) }
178
179 mut main_src := strings.new_builder(96_000)
180 main_src.writeln('module main')
181 main_src.writeln('')
182 main_src.writeln('struct Box[T] {')
183 main_src.writeln(' value T')
184 main_src.writeln('}')
185 main_src.writeln('')
186 main_src.writeln('fn (b Box[T]) accept(x ?T) T {')
187 main_src.writeln(' value := x or {')
188 main_src.writeln(' return b.value')
189 main_src.writeln(' }')
190 main_src.writeln(' return value')
191 main_src.writeln('}')
192 main_src.writeln('')
193 main_src.writeln('fn use_box_accept() int {')
194 main_src.writeln(' b := Box[int]{')
195 main_src.writeln(' value: 5')
196 main_src.writeln(' }')
197 main_src.writeln(' return b.accept(7) + b.accept(8)')
198 main_src.writeln('}')
199 main_src.writeln('')
200 for i in 0 .. 1050 {
201 main_src.writeln('fn helper_${i}() int {')
202 main_src.writeln('\treturn ${i}')
203 main_src.writeln('}')
204 main_src.writeln('')
205 }
206 main_src.writeln('fn main() {')
207 main_src.writeln('\tmut total := use_box_accept()')
208 for i in 0 .. 1050 {
209 main_src.writeln('\ttotal += helper_${i}()')
210 }
211 main_src.writeln('\tprintln(int_str(total))')
212 main_src.writeln('}')
213 os.write_file(os.join_path(project_dir, 'main.v'), main_src.str()) or { panic(err) }
214 return os.join_path(project_dir, 'main.v')
215}
216
217fn test_parallel_cgen_worker_resolves_generic_struct_method_signature() {
218 v3_bin := build_parallel_v3()
219 main_path := write_parallel_generic_struct_method_project('parallel_generic_struct_method')
220 bin_out := os.join_path(os.temp_dir(), 'v3_parallel_generic_struct_method_out')
221 compile := os.execute('VJOBS=2 ${v3_bin} ${main_path} -b c -o ${bin_out}')
222 assert compile.exit_code == 0, compile.output
223 assert compile.output.contains('cgen (parallel)'), compile.output
224 run := os.execute(bin_out)
225 assert run.exit_code == 0, run.output
226 assert run.output.trim_space() == '550740'
227 c_code := os.read_file(bin_out + '.c') or { panic(err) }
228 assert c_code.contains('Box_int__accept'), c_code
229 assert c_code.contains('Optional_int x'), c_code
230 assert !c_code.contains('?T'), c_code
231}
232
233fn write_parallel_top_level_no_main_project(name string) string {
234 project_dir := os.join_path(os.temp_dir(), 'v3_${name}')
235 os.rmdir_all(project_dir) or {}
236 os.mkdir_all(project_dir) or { panic(err) }
237
238 mut main_src := strings.new_builder(48_000)
239 main_src.writeln('module main')
240 main_src.writeln('')
241 for i in 0 .. 320 {
242 main_src.writeln('fn helper_${i}() int {')
243 main_src.writeln('\treturn ${i}')
244 main_src.writeln('}')
245 main_src.writeln('')
246 }
247 main_src.writeln('mut values := map[string]int{}')
248 main_src.writeln("mut total := values['missing'] or {")
249 main_src.writeln('\t7')
250 main_src.writeln('}')
251 for i in 0 .. 320 {
252 main_src.writeln('total += helper_${i}()')
253 }
254 main_src.writeln('println(int_str(total))')
255 os.write_file(os.join_path(project_dir, 'main.v'), main_src.str()) or { panic(err) }
256 return os.join_path(project_dir, 'main.v')
257}
258
259fn test_parallel_transform_lowers_top_level_stmts_without_main_once() {
260 v3_bin := build_parallel_v3()
261 main_path := write_parallel_top_level_no_main_project('parallel_top_level_no_main')
262 bin_out := os.join_path(os.temp_dir(), 'v3_parallel_top_level_no_main_out')
263 compile := os.execute('VJOBS=2 ${v3_bin} --parallel-transform ${main_path} -b c -o ${bin_out}')
264 assert compile.exit_code == 0, compile.output
265 assert compile.output.contains('transform (parallel)'), compile.output
266 assert compile.output.contains('cgen'), compile.output
267 run := os.execute(bin_out)
268 assert run.exit_code == 0, run.output
269 assert run.output.trim_space() == '51047'
270 c_code := os.read_file(bin_out + '.c') or { panic(err) }
271 assert c_code.all_after('int main').count('map__get_check') == 1, c_code
272}
273
274fn test_parallel_transform_selfhost_builds_v3() {
275 v3_bin := build_parallel_prod_v3()
276 bin_out := os.join_path(os.temp_dir(), 'v3_parallel_selfhost_out_${os.getpid()}')
277 os.rm(bin_out) or {}
278 os.rm(bin_out + '.c') or {}
279 compile :=
280 os.execute('VJOBS=2 ${v3_bin} -building-v -parallel-transform -parallel -o ${bin_out} ${parallel_v3_src}')
281 assert compile.exit_code == 0, compile.output
282 assert compile.output.contains('transform (parallel)'), compile.output
283 assert compile.output.contains('cgen (parallel)'), compile.output
284 assert os.exists(bin_out), compile.output
285 c_code := os.read_file(bin_out + '.c') or { panic(err) }
286 assert c_code.contains('Array_u8__bytestr'), c_code
287 assert c_code.contains('Array_u8__hex'), c_code
288}
289