v
v copied to clipboard
cgen: emit a const variable instead of a define
i have removed the comment because i think its saner for the compilers to have a single symbol to track instead of creating a new symbol in memory every time the variable is accessed.
This change introduces some regressions because of bad code:
- spotted some signed vs unsigned comparisons (define -> int)
- this is why the code is commented if
if true {
- this is why the code is commented if
- enforces
constat C level (not just at V) - using more const (and maybe we should also add
staticfor non-pub constants)
This program generates the following C:
$ cat constexpr.v
const myvar = 0 // define instead of const
const mybar = 0.2
const myuar = u64(32)
const myarr = ['123','456']
const mystr = Foo{0}
const mymsg = 'hello'
struct Foo { a int }
$
#define _const_main__myvar 0
f64 _const_main__mybar = 0.2; // precomputed
u64 _const_main__myuar = 32U; // precomputed
Array_string _const_main__myarr; // inited later
main__Foo _const_main__mystr; // inited later
string _const_main__mymsg; // a string literal, inited later
for consistency, and also, in order to export symbols it's better to use const instead of a #define
after this patch it generates:
const int _const_main__myvar = 0;
const f64 _const_main__mybar = 0.2; // precomputed
const u64 _const_main__myuar = 32U; // precomputed
Array_string _const_main__myarr; // inited later
main__Foo _const_main__mystr; // inited later
string _const_main__mymsg; // a string literal, inited later
This change will allow C compilers to do better optimisations 👍
I have compiled a table test as main.v (with -prod there's no difference), but normal compilation results in smaller binary:
master: 636K
nodefine: 628K
the v compiler is also smaller:
5160KB -> 5144KB
So it seems like in general, it makes V programs 15KB smaller
The failing test is tricky.. (only happens in -cstrict).. not sure how should be fixed. this is the file triggering the error:
$ cat b.v
const (
foo = u32(1)
bar = u32(2)
weapon_keys = [&foo, &bar]!
)
fn main() {
assert weapon_keys[0] == &foo
assert weapon_keys[1] == &bar
}
$
which generates
const u32 _const_main__foo = 1; // precomputed
const u32 _const_main__bar = 2; // precomputed
Array_fixed_u32_ptr1_2 _const_main__weapon_keys = {&_const_main__foo, &_const_main__bar}; // fixed array const
the variables are const, which is fine but the array is not of type const so the compiler warns and it fails to compile because the array can hold const and non-const elements.
To fix this we can do different things:
- track the variables that are assigned in fixed arrays and remove the
constattribute (too expensive) - cast on every assignment (u32*) in this case. this will make the code longer. and if the user tries to modify the contents of the elements of the fixed array it will crash (which imho is expected and correct behaviour)
- Make the Array_fixed_u32 type const - this causes other compiler warnings when the contents are taken because the underlying value is not const
typedef u32* Array_fixed_u32_ptr1_2 [2];
->
typedef const u32* Array_fixed_u32_ptr1_2 [2];
So it seems like in general, it makes V programs 15KB smaller
With what platform/compiler was that measured 🤔 ? I got ~400B - ~2.4KB of differences on Ubuntu 20.04 with gcc-11, clang-12 (tcc shows no difference at all).
I've made a script to measure in a more systematic way, and it seems that I am wrong about tcc:
2[15:56:58]delian@nemesis: (master) /v/cleanv $ rm -rf compare_*; for branch in master nodefine; do git checkout $branch; ./v -o v$branch cmd/v; vcompiler=v$branch; for ccompiler in tcc clang-12 gcc-11; do cmd="./$vcompiler -cc $ccompiler -keepc -o compare_${vcompiler}_${ccompiler} cmd/v"; echo $cmd; $cmd; done ; done; ls -larS compare_*;
Already on 'master'
Your branch is up to date with 'origin/master'.
./vmaster -cc tcc -keepc -o compare_vmaster_tcc cmd/v
./vmaster -cc clang-12 -keepc -o compare_vmaster_clang-12 cmd/v
./vmaster -cc gcc-11 -keepc -o compare_vmaster_gcc-11 cmd/v
Switched to branch 'nodefine'
./vnodefine -cc tcc -keepc -o compare_vnodefine_tcc cmd/v
./vnodefine -cc clang-12 -keepc -o compare_vnodefine_clang-12 cmd/v
./vnodefine -cc gcc-11 -keepc -o compare_vnodefine_gcc-11 cmd/v
-rwxrwxr-x 1 delian delian 3152408 Apr 11 15:57 compare_vnodefine_clang-12
-rwxrwxr-x 1 delian delian 3156816 Apr 11 15:57 compare_vmaster_clang-12
-rwxrwxr-x 1 delian delian 3825360 Apr 11 15:58 compare_vnodefine_gcc-11
-rwxrwxr-x 1 delian delian 3825680 Apr 11 15:57 compare_vmaster_gcc-11
-rwxrwxr-x 1 delian delian 8468464 Apr 11 15:57 compare_vnodefine_tcc
-rwxrwxr-x 1 delian delian 8475056 Apr 11 15:57 compare_vmaster_tcc
0[15:58:03]delian@nemesis: (nodefine) /v/cleanv $
Smaller programs like hello_world.v show no big improvement in executable size (~100-450 bytes):
0[16:00:04]delian@nemesis: (nodefine) /v/cleanv $ rm -rf compare_*; for branch in master nodefine; do git checkout $branch; ./v -o v$branch cmd/v; vcompiler=v$branch; for ccompiler in tcc clang-12 gcc-11; do cmd="./$vcompiler -cc $ccompiler -keepc -o compare_${vcompiler}_${ccompiler} examples/hello_world.v"; echo $cmd; $cmd; done ; done; ls -larS compare_*;
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
./vmaster -cc tcc -keepc -o compare_vmaster_tcc examples/hello_world.v
./vmaster -cc clang-12 -keepc -o compare_vmaster_clang-12 examples/hello_world.v
./vmaster -cc gcc-11 -keepc -o compare_vmaster_gcc-11 examples/hello_world.v
Switched to branch 'nodefine'
./vnodefine -cc tcc -keepc -o compare_vnodefine_tcc examples/hello_world.v
./vnodefine -cc clang-12 -keepc -o compare_vnodefine_clang-12 examples/hello_world.v
./vnodefine -cc gcc-11 -keepc -o compare_vnodefine_gcc-11 examples/hello_world.v
-rwxrwxr-x 1 delian delian 230104 Apr 11 16:00 compare_vnodefine_clang-12
-rwxrwxr-x 1 delian delian 230296 Apr 11 16:00 compare_vmaster_clang-12
-rwxrwxr-x 1 delian delian 254048 Apr 11 16:00 compare_vnodefine_gcc-11
-rwxrwxr-x 1 delian delian 254232 Apr 11 16:00 compare_vmaster_gcc-11
-rwxrwxr-x 1 delian delian 606520 Apr 11 16:00 compare_vnodefine_tcc
-rwxrwxr-x 1 delian delian 606976 Apr 11 16:00 compare_vmaster_tcc
0[16:00:40]delian@nemesis: (nodefine) /v/cleanv $
Closing/re-opening, to check status against current V.