compiler: new attributes, prelude customization
parent
748b1d3381
commit
2b27072fac
|
@ -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>.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue