verify: implement P_Array_Append_One
[ajla.git] / newlib / compiler / selfopt.ajla
blob8eb825306006d5ee463371efefc26f3e140f5f3f
1 {*
2  * Copyright (C) 2024, 2025 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  *}
19 private unit compiler.selfopt;
21 uses io;
23 fn self_optimize(w : world, dir : dhandle) : world;
25 implementation
27 uses compiler.common.blob;
28 uses compiler.common.evaluate;
29 uses compiler.parser.unit;
30 uses compiler.parser.util;
31 uses compiler.optimize.utils;
32 uses compiler.optimize.ssa;
34 fn read_dir_recursive(d : dhandle) : list(bytes)
36         var result := empty(bytes);
37         var l := dread_lazy(d);
38         for i := 0 to len(l) do [
39                 var li := l[i];
40                 var t := stat_lazy(d, li, stat_flag_type)[0];
41                 if t = stat_type_file and list_ends_with(li, ".ajla") then [
42                         var str := li[ .. len(li) - 5];
43                         result +<= str;
44                 ]
45                 if t = stat_type_directory then [
46                         var nd := dopen_lazy(d, li, 0);
47                         var dl := read_dir_recursive(nd);
48                         for j := 0 to len(dl) do [
49                                 dl[j] := path_append(li, dl[j]);
50                         ]
51                         result += dl;
52                 ]
53         ]
54         result := list_sort(result);
55         return result;
58 record uni [
59         name : bytes;
60         functions : list(list(pcode_t));
63 fn name_to_ident(n : bytes) : bytes
65         var r := empty(byte);
66         for i := 0 to len(n) do [
67                 if path_is_separator(n[i]) then [
68                         r += "__";
69                 ] else [
70                         r +<= n[i];
71                 ]
72         ]
73         return r;
76 fn get_inline(w : world, d : list(bytes), f : function, optimized : bool) : list(pcode_t)
78         var pc, modules := compile_module_2~save(w, d, f.un, f.program);
79         var pcode1 := pc[f.fn_idx[0]];
80         pcode1 := function_extract_nested(pcode1, f.fn_idx);
81         if not optimized then
82                 return pcode1;
83         var pcode2 := process_pcode(pcode1, get_inline(w, d,,), sysprop(SystemProperty_Verify) <> 0);
84         return pcode2;
87 fn process_nested_functions(pcode1 : list(pcode_t), get_inline : fn(function, bool) : list(pcode_t)) : list(pcode_t)
89         var pcode2 := process_pcode(pcode1, get_inline, sysprop(SystemProperty_Verify) <> 0);
90         var ptr := 9 + blob_length(pcode1[9 .. ]);
91         var pcode_to_insert := empty(pcode_t);
92         for i := 0 to pcode1[2] do [
93                 var sub_pcode := pcode1[ptr + 1 .. ptr + 1 + pcode1[ptr]];
94                 sub_pcode := process_nested_functions(sub_pcode, get_inline);
95                 ptr += 1 + pcode1[ptr];
96                 pcode_to_insert +<= len(sub_pcode);
97                 pcode_to_insert += sub_pcode;
98         ]
99         pcode2[2] := pcode1[2];
100         ptr := 9 + blob_length(pcode1[9 .. ]);
101         pcode2 := pcode2[ .. ptr] + pcode_to_insert + pcode2[ptr .. ];
102         return pcode2;
105 fn optimize_module(w : world, d : list(bytes), u : uni, pc : list(list(pcode_t))) : uni
107         for idx := 0 to len(pc) do [
108                 var pcode1 := pc[idx];
109                 var pcode2 := process_nested_functions(pcode1, get_inline(w, d,,));
110                 u.functions +<= pcode2;
111         ]
112         return u;
115 fn self_optimize(implicit w : world, dir : dhandle) : world
117         var h : handle;
118         var units := empty(uni);
119         var dir_nl := dopen_lazy(dir, "newlib", 0);
120         var l := read_dir_recursive(dir_nl);
121         var d := list(bytes).[ dpath_lazy(dir_nl) ];
122         for i := 0 to len(l) do [
123                 var nm := l[i];
124                 for n := 0 to len(nm) do
125                         if nm[n] = '\' then
126                                 nm[n] := '/';
127                 var u : uni := uni.[ name : nm, functions : empty(list(pcode_t)) ];
128                 var pc, modules := compile_module_2(d, u.name, false);
129                 u := optimize_module(d, u, pc);
130                 units +<= u;
131         ]
133         var a := empty(byte);
134         var module_info := empty(byte);
135         for i := 0 to len(units) do [
136                 var u := units[i];
137                 var function_info := empty(byte);
138                 for j := 0 to len(u.functions) do [
139                         var function := u.functions[j];
140                         function_info += int_to_native(native.n_int32, len(a));
141                         function_info += int_to_native(native.n_int32, len(function));
142                         var lf := len(function);
143                         for k := 0 to lf do
144                                 a += int_to_native(native.n_int32, function[k]);
145                 ]
146                 module_info += int_to_native(native.n_int32, len(a));
147                 module_info += int_to_native(native.n_int32, len(u.functions));
148                 a += function_info;
149                 a += int_to_native(native.n_int32, len(u.name));
150                 for i := 0 to len(u.name) do
151                         a += int_to_native(native.n_int32, u.name[i]);
152         ]
153         var file_info := empty(byte);
154         file_info += int_to_native(native.n_int32, len(a));
155         file_info += int_to_native(native.n_int32, len(units));
156         file_info += int_to_native(native.n_int32, #616C6A41);
157         a += module_info;
158         a += file_info;
159         h := wopen(dir, "builtin.tmp", open_flag_create, open_mode_default);
160         write(h, a);
161         rename(dir, "builtin.pcd", dir, "builtin.tmp");