From 2e8cc75e5feddd699718d53081d94104ba84960a Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 2 Sep 2025 12:48:51 -0300 Subject: [PATCH] markused: cleanup the generated c code (#25210) --- cmd/tools/vast/vast.v | 3 +++ vlib/v/ast/ast.v | 4 ++++ vlib/v/ast/table.v | 4 ++++ vlib/v/gen/c/cgen.v | 10 +++++++++ vlib/v/gen/c/cheaders.v | 34 +++++++++++++++---------------- vlib/v/gen/c/consts_and_globals.v | 7 ++++--- vlib/v/gen/c/fn.v | 2 +- vlib/v/markused/walker.v | 14 +++++++------ vlib/v/parser/fn.v | 5 +++++ vlib/v/parser/parser.v | 6 ++++++ vlib/v/parser/struct.v | 1 + 11 files changed, 62 insertions(+), 28 deletions(-) diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 5e2ba843b2..d38a95accb 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -596,6 +596,7 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node { obj.add_terse('is_variadic', t.bool_node(node.is_variadic)) obj.add('is_anon', t.bool_node(node.is_anon)) obj.add_terse('is_noreturn', t.bool_node(node.is_noreturn)) + obj.add_terse('is_weak', t.bool_node(node.is_weak)) obj.add_terse('is_manualfree', t.bool_node(node.is_manualfree)) obj.add('is_main', t.bool_node(node.is_main)) obj.add('is_test', t.bool_node(node.is_test)) @@ -840,6 +841,8 @@ fn (t Tree) global_field(node ast.GlobalField) &Node { obj.add_terse('typ', t.type_node(node.typ)) obj.add_terse('has_expr', t.bool_node(node.has_expr)) obj.add_terse('is_markused', t.bool_node(node.is_markused)) + obj.add_terse('is_weak', t.bool_node(node.is_weak)) + obj.add_terse('is_hidden', t.bool_node(node.is_hidden)) obj.add('comments', t.array_node_comment(node.comments)) obj.add('pos', t.pos(node.pos)) obj.add('typ_pos', t.pos(node.typ_pos)) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 484ab59c3f..cdf72c96f7 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -446,6 +446,7 @@ pub: module_pos int = -1 // module: is_union bool is_option bool + is_aligned bool attrs []Attr pre_comments []Comment end_comments []Comment @@ -593,6 +594,7 @@ pub: is_c_extern bool is_variadic bool is_anon bool + is_weak bool is_noreturn bool // true, when @[noreturn] is used on a fn is_manualfree bool // true, when @[manualfree] is used on a fn is_main bool // true for `fn main()` @@ -967,6 +969,8 @@ pub: is_markused bool // an explicit `@[markused]` tag; the global will NOT be removed by `-skip-unused` is_volatile bool is_exported bool // an explicit `@[export]` tag; the global will NOT be removed by `-skip-unused` + is_weak bool + is_hidden bool pub mut: expr Expr typ Type diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 3d01708eed..5443519302 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -38,6 +38,10 @@ pub mut: // json bool // json is imported comptime_calls map[string]bool // resolved name to call on comptime comptime_syms map[Type]bool // resolved syms (generic) + // + used_attr_noreturn bool // @[noreturn] + used_attr_hidden bool // @[hidden] + used_attr_weak bool // @[weak] } @[unsafe] diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 210e8d80df..c1e0368510 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1001,6 +1001,16 @@ pub fn (mut g Gen) init() { } else { g.cheaders.writeln(c_headers) } + if !g.pref.skip_unused || g.table.used_features.used_attr_weak { + g.cheaders.writeln(c_common_weak_attr) + } + if !g.pref.skip_unused || g.table.used_features.used_attr_hidden { + g.cheaders.writeln(c_common_hidden_attr) + } + if !g.pref.skip_unused || g.table.used_features.used_attr_noreturn { + g.cheaders.writeln(c_common_noreturn_attr) + g.cheaders.writeln(c_common_unreachable_attr) + } if !g.pref.skip_unused || g.table.used_features.used_maps > 0 { g.cheaders.writeln(c_wyhash_headers) } diff --git a/vlib/v/gen/c/cheaders.v b/vlib/v/gen/c/cheaders.v index 554086db64..50718595f0 100644 --- a/vlib/v/gen/c/cheaders.v +++ b/vlib/v/gen/c/cheaders.v @@ -180,8 +180,6 @@ const c_common_macros = ' #endif #endif -#define OPTION_CAST(x) (x) - #if defined(_WIN32) || defined(__CYGWIN__) #define VV_EXP extern __declspec(dllexport) #define VV_LOC static @@ -220,7 +218,17 @@ const c_common_macros = ' #undef __has_include #endif +//likely and unlikely macros +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + #define _likely_(x) __builtin_expect(x,1) + #define _unlikely_(x) __builtin_expect(x,0) +#else + #define _likely_(x) (x) + #define _unlikely_(x) (x) +#endif +' +const c_common_weak_attr = ' #if !defined(VWEAK) #define VWEAK __attribute__((weak)) #ifdef _MSC_VER @@ -232,7 +240,9 @@ const c_common_macros = ' #define VWEAK #endif #endif +' +const c_common_hidden_attr = ' #if !defined(VHIDDEN) #define VHIDDEN __attribute__((visibility("hidden"))) #ifdef _MSC_VER @@ -244,7 +254,9 @@ const c_common_macros = ' #define VHIDDEN #endif #endif +' +const c_common_noreturn_attr = ' #if !defined(VNORETURN) #if defined(__TINYC__) #include @@ -259,7 +271,9 @@ const c_common_macros = ' #define VNORETURN #endif #endif +' +const c_common_unreachable_attr = ' #if !defined(VUNREACHABLE) #if defined(__GNUC__) && !defined(__clang__) #define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) @@ -276,16 +290,6 @@ const c_common_macros = ' #define VUNREACHABLE() do { } while (0) #endif #endif - -//likely and unlikely macros -#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) - #define _likely_(x) __builtin_expect(x,1) - #define _unlikely_(x) __builtin_expect(x,0) -#else - #define _likely_(x) (x) - #define _unlikely_(x) (x) -#endif - ' const c_unsigned_comparison_functions = ' @@ -433,8 +437,6 @@ void v_free(voidptr ptr); #define _Atomic volatile // MSVC cannot parse some things properly - #undef OPTION_CAST - #define OPTION_CAST(x) #undef __NOINLINE #undef __IRQHANDLER #define __NOINLINE __declspec(noinline) @@ -451,9 +453,6 @@ void v_free(voidptr ptr); #endif #endif -// g_live_info is used by live.info() -static void* g_live_info = NULL; - #if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__)) #undef PRId64 #undef PRIi64 @@ -711,5 +710,4 @@ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; #endif #define _IN_MAP(val, m) map_exists(m, val) - ' diff --git a/vlib/v/gen/c/consts_and_globals.v b/vlib/v/gen/c/consts_and_globals.v index cf9f0042be..756843cfb0 100644 --- a/vlib/v/gen/c/consts_and_globals.v +++ b/vlib/v/gen/c/consts_and_globals.v @@ -437,13 +437,14 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { should_init := (!g.pref.use_cache && g.pref.build_mode != .build_module) || (g.pref.build_mode == .build_module && g.module_built == node.mod) mut attributes := '' - if node.attrs.contains('weak') { + first_field := node.fields[0] + if first_field.is_weak { attributes += 'VWEAK ' } - if node.attrs.contains('hidden') { + if first_field.is_hidden { attributes += 'VHIDDEN ' } - if node.attrs.contains('export') { + if first_field.is_exported { attributes += 'VV_EXP ' } if attr := node.attrs.find_first('_linker_section') { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 34a0835e70..f371e032ea 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -532,9 +532,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list { println(g.out.after(fn_start_pos)) } + weak := if node.is_weak { 'VWEAK ' } else { '' } for attr in node.attrs { if attr.name == 'export' { - weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' } g.writeln('// export alias: ${attr.arg} -> ${name}') g.export_funcs << attr.arg export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})' diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index f378d4244f..ecbf77fe99 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -142,6 +142,9 @@ pub fn (mut w Walker) mark_global_as_used(ckey string) { } w.used_globals[ckey] = true gfield := w.all_globals[ckey] or { return } + w.table.used_features.used_attr_weak = w.table.used_features.used_attr_weak || gfield.is_weak + w.table.used_features.used_attr_hidden = w.table.used_features.used_attr_hidden + || gfield.is_hidden || gfield.is_hidden w.expr(gfield.expr) if !gfield.has_expr { w.mark_by_type(gfield.typ) @@ -355,9 +358,7 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) { w.mark_by_type(typ.typ) } w.struct_fields(node.fields) - if !w.uses_mem_align { - w.uses_mem_align = node.attrs.contains('aligned') - } + w.uses_mem_align = w.uses_mem_align || node.is_aligned } ast.DeferStmt { w.stmts(node.stmts) @@ -894,6 +895,9 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { w.is_builtin_mod = last_is_builtin_mod } } + w.table.used_features.used_attr_weak = w.table.used_features.used_attr_weak || node.is_weak + w.table.used_features.used_attr_noreturn = w.table.used_features.used_attr_noreturn + || node.is_noreturn if node.language == .c { w.mark_fn_as_used(node.fkey()) w.mark_fn_ret_and_params(node.return_type, node.params) @@ -1153,9 +1157,7 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { } if decl := w.all_structs[isym.name] { w.struct_fields(decl.fields) - if !w.uses_mem_align { - w.uses_mem_align = decl.attrs.contains('aligned') - } + w.uses_mem_align = w.uses_mem_align || decl.is_aligned for iface_typ in decl.implements_types { w.mark_by_type(iface_typ.typ) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 8dd3ac1594..96403cdf5f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -213,6 +213,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut is_c2v_variadic := false mut is_c_extern := false mut is_markused := false + mut is_weak := false mut is_expand_simple_interpolation := false mut comments := []ast.Comment{} fn_attrs := p.attrs @@ -254,6 +255,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl { 'c2v_variadic' { is_c2v_variadic = true } + 'weak' { + is_weak = true + } 'use_new' { is_ctor_new = true } @@ -706,6 +710,7 @@ run them via `v file.v` instead', is_unsafe: is_unsafe is_must_use: is_must_use is_markused: is_markused + is_weak: is_weak is_file_translated: p.is_translated // attrs: fn_attrs diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 20abc5cc64..089d8ba797 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2599,10 +2599,14 @@ fn (mut p Parser) global_decl() ast.GlobalDecl { mut is_markused := false mut is_exported := false + mut is_weak := false + mut is_hidden := false for ga in attrs { match ga.name { 'export' { is_exported = true } 'markused' { is_markused = true } + 'weak' { is_weak = true } + 'hidden' { is_hidden = true } else {} } } @@ -2687,6 +2691,8 @@ fn (mut p Parser) global_decl() ast.GlobalDecl { is_markused: is_markused is_volatile: is_volatile is_exported: is_exported + is_weak: is_weak + is_hidden: is_hidden } fields << field if name !in ast.global_reserved_type_names { diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 87a8b560d0..dc136d84c1 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -480,6 +480,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { language: language is_union: is_union is_option: is_option + is_aligned: attrs.contains('aligned') attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes pre_comments: pre_comments end_comments: end_comments