compiler: new attributes, prelude customization

pull/5050/head
Julia K 2020-05-26 14:12:18 +02:00 committed by GitHub
parent 748b1d3381
commit 2b27072fac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 15 deletions

View File

@ -62,3 +62,11 @@ These build flags are enabled on `build` and `run` as long as the backend is set
-shared
Tell V to compile a shared object instead of an executable.
The resulting file extension will be `.dll` on Windows and `.so` on Unix systems
-no-prelude
Prevents V from generating a prelude in generated .c files, useful for freestanding targets
where eg. you replace C standard library with your own, or some definitions/headers break something.
-custom-prelude <path>
Useful for similar use-case as above option, except it replaces V-generated prelude with
your custom one loaded from specified <path>.

View File

@ -212,13 +212,21 @@ pub fn (g Gen) hashes() string {
}
pub fn (mut g Gen) init() {
g.cheaders.writeln('// Generated by the V compiler')
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
g.cheaders.writeln(c_builtin_types)
g.cheaders.writeln(c_headers)
g.definitions.writeln('\nvoid _STR_PRINT_ARG(const char*, char**, int*, int*, int, ...);\n')
g.definitions.writeln('\nstring _STR(const char*, int, ...);\n')
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
if g.pref.custom_prelude != '' {
g.cheaders.writeln(g.pref.custom_prelude)
} else if !g.pref.no_preludes {
g.cheaders.writeln('// Generated by the V compiler')
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
g.cheaders.writeln(c_builtin_types)
if g.pref.is_bare {
g.cheaders.writeln(bare_c_headers)
} else {
g.cheaders.writeln(c_headers)
}
g.definitions.writeln('\nvoid _STR_PRINT_ARG(const char*, char**, int*, int*, int, ...);\n')
g.definitions.writeln('\nstring _STR(const char*, int, ...);\n')
g.definitions.writeln('\nstring _STR_TMP(const char*, ...);\n')
}
g.write_builtin_types()
g.write_typedef_types()
g.write_typeof_functions()

View File

@ -27,6 +27,9 @@ const (
#define EMPTY_ARRAY_OF_ELEMS(x,n) (x[])
#define TCCSKIP(x) x
#define __NOINLINE __attribute__((noinline))
#define __IRQHANDLER __attribute__((interrupt))
#ifdef __TINYC__
#undef EMPTY_STRUCT_DECLARATION
#undef EMPTY_STRUCT_INITIALIZATION
@ -34,6 +37,11 @@ const (
#define EMPTY_STRUCT_INITIALIZATION 0
#undef EMPTY_ARRAY_OF_ELEMS
#define EMPTY_ARRAY_OF_ELEMS(x,n) (x[n])
#undef __NOINLINE
#undef __IRQHANDLER
// tcc does not support inlining at all
#define __NOINLINE
#define __IRQHANDLER
#undef TCCSKIP
#define TCCSKIP(x)
#include <byteswap.h>
@ -178,12 +186,15 @@ $c_common_macros
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable
#define OPTION_CAST(x)
#undef __NOINLINE
#undef __IRQHANDLER
#define __NOINLINE __declspec(noinline)
#define __IRQHANDLER __declspec(naked)
#include <dbghelp.h>
#pragma comment(lib, "Dbghelp.lib")
extern wchar_t **_wenviron;
#endif
#else

View File

@ -37,9 +37,71 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
}
//
fn_start_pos := g.out.len
if g.attr == 'inline' {
g.write('inline ')
match g.attr {
'inline' {
g.write('inline ')
}
// since these are supported by GCC, clang and MSVC, we can consider them officially supported.
'no_inline' {
g.write('__NOINLINE')
}
'irq_handler' {
g.write('__IRQHANDLER ')
}
// GCC/clang attributes
// prefixed by _ to indicate they're for advanced users only and not really supported by V.
// source for descriptions: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
// The cold attribute on functions is used to inform the compiler that the function is unlikely
// to be executed. The function is optimized for size rather than speed and on many targets it
// is placed into a special subsection of the text section so all cold functions appear close
// together, improving code locality of non-cold parts of program.
'_cold' {
g.write('__attribute__((cold))')
}
// The constructor attribute causes the function to be called automatically before execution
// enters main ().
'_constructor' {
g.write('__attribute__((constructor))')
}
// The destructor attribute causes the function to be called automatically after main ()
// completes or exit () is called.
'_destructor' {
g.write('__attribute__((destructor))')
}
// Generally, inlining into a function is limited. For a function marked with this attribute,
// every call inside this function is inlined, if possible.
'_flatten' {
g.write('__attribute__((flatten))')
}
// The hot attribute on a function is used to inform the compiler that the function is a hot
// spot of the compiled program.
'_hot' {
g.write('__attribute__((hot))')
}
// This tells the compiler that a function is malloc-like, i.e., that the pointer P returned by
// the function cannot alias any other pointer valid when the function returns, and moreover no
// pointers to valid objects occur in any storage addressed by P.
'_malloc' {
g.write('__attribute__((malloc))')
}
// Calls to functions whose return value is not affected by changes to the observable state
// of the program and that have no observable effects on such state other than to return a
// value may lend themselves to optimizations such as common subexpression elimination.
// Declaring such functions with the const attribute allows GCC to avoid emitting some calls in
// repeated invocations of the function with the same argument values.
'_pure' {
g.write('__attribute__((const)) ')
}
else {
// nothing but keep V happy
}
}
// todo: Clang/GCC only
//
is_livefn := g.attr == 'live'
is_livemain := g.pref.is_livemain && is_livefn

View File

@ -90,6 +90,8 @@ pub mut:
enable_globals bool // allow __global for low level code
is_fmt bool
is_bare bool
no_preludes bool // Prevents V from generating preludes in resulting .c files
custom_prelude string // Contents of custom V prelude that will be prepended before code in resulting .c files
lookup_path []string
output_cross_c bool
prealloc bool
@ -143,7 +145,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
'-shared' {
res.is_shared = true
}
'--enable-globals' {
'--enable-globals', '-enable-globals' {
res.enable_globals = true
}
'-autofree' {
@ -155,6 +157,9 @@ pub fn parse_args(args []string) (&Preferences, string) {
'-freestanding' {
res.is_bare = true
}
'-no-preludes' {
res.no_preludes = true
}
'-prof', '-profile' {
res.profile_file = cmdline.option(current_args, '-profile', '-')
res.is_prof = true
@ -176,10 +181,10 @@ pub fn parse_args(args []string) (&Preferences, string) {
res.translated = true
}
'-color' {
res.use_color=.always
res.use_color = .always
}
'-nocolor' {
res.use_color=.never
res.use_color = .never
}
'-showcc' {
res.show_cc = true
@ -203,7 +208,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
res.print_v_files = true
}
'-error-limit' {
res.error_limit =cmdline.option(current_args, '-error-limit', '0').int()
res.error_limit = cmdline.option(current_args, '-error-limit', '0').int()
}
'-os' {
target_os := cmdline.option(current_args, '-os', '')
@ -213,7 +218,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
res.output_cross_c = true
continue
}
println('unknown operating system target `$target_os`')
eprintln('unknown operating system target `$target_os`')
exit(1)
}
res.os = target_os_kind
@ -253,6 +258,15 @@ pub fn parse_args(args []string) (&Preferences, string) {
res.lookup_path = path.split(os.path_delimiter)
i++
}
'-custom-prelude' {
path := cmdline.option(current_args, '-custom-prelude', '')
prelude := os.read_file(path) or {
eprintln('cannot open custom prelude file: $err')
exit(1)
}
res.custom_prelude = prelude
i++
}
else {
mut should_continue := false
for flag_with_param in list_of_flags_with_param {