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
$if !no_bounds_checking {
if start > end {
panic('array.slice: invalid slice index (start>end):' + i64(start).str() + ', ' +
i64(end).str())
panic('array.slice: invalid slice index (start>end):' + impl_i64_to_string(i64(start)) +
', ' + impl_i64_to_string(end))
}
if end > a.len {
panic('array.slice: slice bounds out of range (' + i64(end).str() + ' >= ' +
i64(a.len).str() + ')')
panic('array.slice: slice bounds out of range (' + impl_i64_to_string(end) + ' >= ' +
impl_i64_to_string(a.len) + ')')
}
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

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.
@[noreturn]
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.
@[noreturn]
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.
@[noreturn]
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`

View File

@ -11,7 +11,7 @@ pub type byte = u8
// ptr_str returns a string with the address of `ptr`.
pub fn ptr_str(ptr voidptr) string {
buf1 := u64(ptr).hex()
buf1 := u64_to_hex_no_leading_zeros(u64(ptr), 16)
return buf1
}
@ -182,13 +182,18 @@ pub fn (nn u32) str() string {
// str returns the value of the `int_literal` as a `string`.
@[inline]
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`.
// Example: assert i64(-200000).str() == '-200000'
@[direct_array_access; inline]
@[inline]
pub fn (nn i64) str() string {
return impl_i64_to_string(nn)
}
@[direct_array_access]
fn impl_i64_to_string(nn i64) string {
unsafe {
mut n := nn
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
$if !no_bounds_checking {
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
panic('substr(' + start.str() + ', ' + end.str() + ') out of bounds (len=' +
s.len.str() + ') s=' + s)
panic('substr(' + impl_i64_to_string(start) + ', ' + impl_i64_to_string(end) +
') out of bounds (len=' + impl_i64_to_string(s.len) + ') s=' + s)
}
}
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 {
end := if _end == max_int { s.len } else { _end } // max_int
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
return error('substr(' + start.str() + ', ' + end.str() + ') out of bounds (len=' +
s.len.str() + ')')
return error('substr(' + impl_i64_to_string(start) + ', ' + impl_i64_to_string(end) +
') out of bounds (len=' + impl_i64_to_string(s.len) + ')')
}
len := end - start
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(
table: table
files: ast_files
all_fns: all_fns
all_consts: all_consts
all_globals: all_globals

View File

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