builtin,markused: consider println of non string to use .str() method calls too, reduce generated C code for v -cc gcc examples/hello_world.v (#24996)

This commit is contained in:
Delyan Angelov 2025-07-29 14:52:24 +03:00 committed by GitHub
parent 2c8685a386
commit eb99497ffc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 43 additions and 30 deletions

View File

@ -563,15 +563,15 @@ fn (a array) slice(start int, _end int) array {
end := if _end == max_int { a.len } else { _end } // max_int end := if _end == max_int { a.len } else { _end } // max_int
$if !no_bounds_checking { $if !no_bounds_checking {
if start > end { if start > end {
panic('array.slice: invalid slice index (start>end):' + i64(start).str() + ', ' + panic('array.slice: invalid slice index (start>end):' + impl_i64_to_string(i64(start)) +
i64(end).str()) ', ' + impl_i64_to_string(end))
} }
if end > a.len { if end > a.len {
panic('array.slice: slice bounds out of range (' + i64(end).str() + ' >= ' + panic('array.slice: slice bounds out of range (' + impl_i64_to_string(end) + ' >= ' +
i64(a.len).str() + ')') impl_i64_to_string(a.len) + ')')
} }
if start < 0 { if start < 0 {
panic('array.slice: slice bounds out of range (start<0):' + start.str()) panic('array.slice: slice bounds out of range (start<0):' + impl_i64_to_string(start))
} }
} }
// TODO: integrate reference counting // TODO: integrate reference counting

View File

@ -184,19 +184,20 @@ pub fn c_error_number_str(errnum int) string {
// panic_n prints an error message, followed by the given number, then exits the process with exit code of 1. // panic_n prints an error message, followed by the given number, then exits the process with exit code of 1.
@[noreturn] @[noreturn]
pub fn panic_n(s string, number1 i64) { pub fn panic_n(s string, number1 i64) {
panic(s + number1.str()) panic(s + impl_i64_to_string(number1))
} }
// panic_n2 prints an error message, followed by the given numbers, then exits the process with exit code of 1. // panic_n2 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
@[noreturn] @[noreturn]
pub fn panic_n2(s string, number1 i64, number2 i64) { pub fn panic_n2(s string, number1 i64, number2 i64) {
panic(s + number1.str() + ', ' + number2.str()) panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2))
} }
// panic_n3 prints an error message, followed by the given numbers, then exits the process with exit code of 1. // panic_n3 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
@[noreturn] @[noreturn]
fn panic_n3(s string, number1 i64, number2 i64, number3 i64) { fn panic_n3(s string, number1 i64, number2 i64, number3 i64) {
panic(s + number1.str() + ', ' + number2.str() + ', ' + number2.str()) panic(s + impl_i64_to_string(number1) + ', ' + impl_i64_to_string(number2) + ', ' +
impl_i64_to_string(number2))
} }
// panic with a C-API error message matching `errnum` // panic with a C-API error message matching `errnum`

View File

@ -11,7 +11,7 @@ pub type byte = u8
// ptr_str returns a string with the address of `ptr`. // ptr_str returns a string with the address of `ptr`.
pub fn ptr_str(ptr voidptr) string { pub fn ptr_str(ptr voidptr) string {
buf1 := u64(ptr).hex() buf1 := u64_to_hex_no_leading_zeros(u64(ptr), 16)
return buf1 return buf1
} }
@ -182,13 +182,18 @@ pub fn (nn u32) str() string {
// str returns the value of the `int_literal` as a `string`. // str returns the value of the `int_literal` as a `string`.
@[inline] @[inline]
pub fn (n int_literal) str() string { pub fn (n int_literal) str() string {
return i64(n).str() return impl_i64_to_string(n)
} }
// str returns the value of the `i64` as a `string`. // str returns the value of the `i64` as a `string`.
// Example: assert i64(-200000).str() == '-200000' // Example: assert i64(-200000).str() == '-200000'
@[direct_array_access; inline] @[inline]
pub fn (nn i64) str() string { pub fn (nn i64) str() string {
return impl_i64_to_string(nn)
}
@[direct_array_access]
fn impl_i64_to_string(nn i64) string {
unsafe { unsafe {
mut n := nn mut n := nn
mut d := i64(0) mut d := i64(0)

View File

@ -1168,8 +1168,8 @@ pub fn (s string) substr(start int, _end int) string {
end := if _end == max_int { s.len } else { _end } // max_int end := if _end == max_int { s.len } else { _end } // max_int
$if !no_bounds_checking { $if !no_bounds_checking {
if start > end || start > s.len || end > s.len || start < 0 || end < 0 { if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
panic('substr(' + start.str() + ', ' + end.str() + ') out of bounds (len=' + panic('substr(' + impl_i64_to_string(start) + ', ' + impl_i64_to_string(end) +
s.len.str() + ') s=' + s) ') out of bounds (len=' + impl_i64_to_string(s.len) + ') s=' + s)
} }
} }
len := end - start len := end - start
@ -1207,8 +1207,8 @@ pub fn (s string) substr_unsafe(start int, _end int) string {
pub fn (s string) substr_with_check(start int, _end int) !string { pub fn (s string) substr_with_check(start int, _end int) !string {
end := if _end == max_int { s.len } else { _end } // max_int end := if _end == max_int { s.len } else { _end } // max_int
if start > end || start > s.len || end > s.len || start < 0 || end < 0 { if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
return error('substr(' + start.str() + ', ' + end.str() + ') out of bounds (len=' + return error('substr(' + impl_i64_to_string(start) + ', ' + impl_i64_to_string(end) +
s.len.str() + ')') ') out of bounds (len=' + impl_i64_to_string(s.len) + ')')
} }
len := end - start len := end - start
if len == s.len { if len == s.len {

View File

@ -311,7 +311,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
mut walker := Walker.new( mut walker := Walker.new(
table: table table: table
files: ast_files
all_fns: all_fns all_fns: all_fns
all_consts: all_consts all_consts: all_consts
all_globals: all_globals all_globals: all_globals

View File

@ -23,7 +23,6 @@ pub mut:
used_panic int // option/result propagation used_panic int // option/result propagation
pref &pref.Preferences = unsafe { nil } pref &pref.Preferences = unsafe { nil }
mut: mut:
files []&ast.File
all_fns map[string]ast.FnDecl all_fns map[string]ast.FnDecl
all_consts map[string]ast.ConstField all_consts map[string]ast.ConstField
all_globals map[string]ast.GlobalField all_globals map[string]ast.GlobalField
@ -55,8 +54,8 @@ mut:
uses_interp bool // string interpolation uses_interp bool // string interpolation
uses_guard bool uses_guard bool
uses_orm bool uses_orm bool
uses_str bool // has .str() call uses_str map[ast.Type]bool // has .str() calls, and for which types
uses_free bool // has .free() call uses_free map[ast.Type]bool // has .free() calls, and for which types
uses_spawn bool uses_spawn bool
uses_dump bool uses_dump bool
uses_memdup bool // sumtype cast and &Struct{} uses_memdup bool // sumtype cast and &Struct{}
@ -107,9 +106,6 @@ pub fn (mut w Walker) mark_const_as_used(ckey string) {
return return
} }
w.used_consts[ckey] = true w.used_consts[ckey] = true
if ckey == 'c' {
println(ckey)
}
cfield := w.all_consts[ckey] or { return } cfield := w.all_consts[ckey] or { return }
w.expr(cfield.expr) w.expr(cfield.expr)
w.mark_by_type(cfield.typ) w.mark_by_type(cfield.typ)
@ -428,10 +424,13 @@ fn (mut w Walker) expr(node_ ast.Expr) {
if sym.info is ast.Map { if sym.info is ast.Map {
w.mark_by_type(w.table.find_or_register_array(sym.info.key_type)) w.mark_by_type(w.table.find_or_register_array(sym.info.key_type))
} }
} else if !w.uses_str && node.is_method && node.name == 'str' { } else if !node.is_method && node.args.len == 1 && node.args[0].typ != ast.string_type
w.uses_str = true && node.name in ['println', 'print', 'eprint', 'eprintln'] {
} else if !w.uses_free && node.is_method && node.name == 'free' { w.uses_str[node.args[0].typ] = true
w.uses_free = true } else if node.is_method && node.name == 'str' {
w.uses_str[node.left_type] = true
} else if node.is_method && node.name == 'free' {
w.uses_free[node.left_type] = true
} }
if !w.is_builtin_mod && !w.uses_external_type { if !w.is_builtin_mod && !w.uses_external_type {
if node.is_method { if node.is_method {
@ -1295,18 +1294,27 @@ fn (mut w Walker) mark_resource_dependencies() {
if w.uses_arr_void { if w.uses_arr_void {
w.mark_by_type(w.table.find_or_register_array(ast.voidptr_type)) w.mark_by_type(w.table.find_or_register_array(ast.voidptr_type))
} }
for typ, _ in w.table.used_features.print_types {
w.mark_by_type(typ)
}
if w.trace_enabled { if w.trace_enabled {
types := w.table.used_features.print_types.keys().map(w.table.type_to_str(it)) types := w.table.used_features.print_types.keys().map(w.table.type_to_str(it))
eprintln('>>>>>>>>>> PRINT TYPES ${types}') eprintln('>>>>>>>>>> PRINT TYPES ${types}')
} }
for typ, _ in w.table.used_features.print_types { if w.trace_enabled {
w.mark_by_type(typ) types := w.uses_str.keys().map(w.table.type_to_str(it))
eprintln('>>>>>>>>>> USES .str() CALLS ON TYPES ${types}')
}
if w.trace_enabled {
types := w.uses_free.keys().map(w.table.type_to_str(it))
eprintln('>>>>>>>>>> USES .free() CALLS ON TYPES ${types}')
} }
if w.trace_enabled { if w.trace_enabled {
eprintln('>>>>>>>>>> ALL_FNS LOOP') eprintln('>>>>>>>>>> ALL_FNS LOOP')
} }
mut has_ptr_print := false mut has_ptr_print := false
has_str_call := w.uses_interp || w.uses_asserts || w.uses_str || w.features.print_types.len > 0 has_str_call := w.uses_interp || w.uses_asserts || w.uses_str.len > 0
|| w.features.print_types.len > 0
for k, mut func in w.all_fns { for k, mut func in w.all_fns {
if has_str_call && k.ends_with('.str') { if has_str_call && k.ends_with('.str') {
if func.receiver.typ.idx() in w.used_syms { if func.receiver.typ.idx() in w.used_syms {
@ -1318,7 +1326,7 @@ fn (mut w Walker) mark_resource_dependencies() {
} }
continue continue
} }
if w.pref.autofree || (w.uses_free && k.ends_with('.free') if w.pref.autofree || (w.uses_free.len > 0 && k.ends_with('.free')
&& func.receiver.typ.idx() in w.used_syms) { && func.receiver.typ.idx() in w.used_syms) {
w.fn_by_name(k) w.fn_by_name(k)
continue continue