Skip to content

Commit 59f02e4

Browse files
committed
cgen: route integer interpolation through str_intp
1 parent 1218aec commit 59f02e4

4 files changed

Lines changed: 77 additions & 11 deletions

File tree

vlib/v/gen/c/coutput_test.v

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ fn test_simple_string_interpolation_does_not_emit_str_intp_runtime() {
339339
os.chdir(vroot) or {}
340340
test_source := os.join_path(os.vtmp_dir(), 'coutput_simple_interpolation_no_str_intp.vv')
341341
os.write_file(test_source,
342-
"module main\n\nimport time\n\nfn main() {\n\tt := time.now()\n\tprintln('elapsed \${time.since(t)}')\n}\n")!
342+
"module main\n\nfn label() string {\n\treturn 'V'\n}\n\nfn main() {\n\tprintln('elapsed \${label()}')\n}\n")!
343343
defer {
344344
os.rm(test_source) or {}
345345
}
@@ -350,6 +350,28 @@ fn test_simple_string_interpolation_does_not_emit_str_intp_runtime() {
350350
assert !compilation.output.contains('StrIntpData')
351351
}
352352

353+
fn test_skip_unused_os_integer_interpolation_keeps_str_intp_runtime() {
354+
os.chdir(vroot) or {}
355+
os_function_source := os.join_path(vroot, 'vlib/os/coutput_skip_unused_int_interpolation.v')
356+
test_source := os.join_path(os.vtmp_dir(), 'coutput_os_int_interpolation.vv')
357+
pexe := os.join_path(os.vtmp_dir(), 'coutput_os_int_interpolation.exe')
358+
os.write_file(os_function_source,
359+
"module os\n\npub fn coutput_skip_unused_int_interpolation(n int) string {\n\treturn '\${n}'\n}\n")!
360+
os.write_file(test_source,
361+
'module main\n\nimport os\n\nfn main() {\n\tprintln(os.coutput_skip_unused_int_interpolation(7))\n}\n')!
362+
defer {
363+
os.rm(os_function_source) or {}
364+
os.rm(test_source) or {}
365+
os.rm(pexe) or {}
366+
}
367+
cmd := '${os.quoted_path(vexe)} -skip-unused -o ${os.quoted_path(pexe)} ${os.quoted_path(test_source)}'
368+
compilation := os.execute(cmd)
369+
ensure_compilation_succeeded(compilation, cmd)
370+
res := os.execute(os.quoted_path(pexe))
371+
assert res.exit_code == 0
372+
assert res.output.trim_space() == '7'
373+
}
374+
353375
fn test_auto_str_float_array_still_emits_str_intp_runtime() {
354376
os.chdir(vroot) or {}
355377
test_source := os.join_path(os.vtmp_dir(), 'coutput_float_array_str_intp.vv')

vlib/v/gen/c/str_intp.v

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,19 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
838838

839839
const simple_string_interpolation_default_precision = 987698
840840

841+
fn (mut g Gen) simple_string_interpolation_needs_str_intp(typ ast.Type) bool {
842+
if g.is_builtin_mod {
843+
return false
844+
}
845+
if typ.has_option_or_result() {
846+
return false
847+
}
848+
resolved_typ := g.unwrap_generic(typ).clear_flags()
849+
return resolved_typ in [ast.i8_type, ast.i16_type, ast.i32_type, ast.int_type, ast.i64_type,
850+
ast.isize_type, ast.u8_type, ast.u16_type, ast.u32_type, ast.u64_type, ast.usize_type,
851+
ast.int_literal_type]
852+
}
853+
841854
fn (mut g Gen) gen_simple_string_inter_literal(node ast.StringInterLiteral, fmts []u8) bool {
842855
if g.is_autofree || g.pref.gc_mode == .boehm_leak {
843856
// The fast `string_plus_many` lowering can leave nested temporary
@@ -852,6 +865,9 @@ fn (mut g Gen) gen_simple_string_inter_literal(node ast.StringInterLiteral, fmts
852865
if i >= node.need_fmts.len || node.need_fmts[i] || i >= fmts.len || fmts[i] == `_` {
853866
return false
854867
}
868+
if g.simple_string_interpolation_needs_str_intp(node.expr_types[i]) {
869+
return false
870+
}
855871
normalized_expr_type := g.table.fully_unaliased_type(g.unwrap_generic(node.expr_types[i]))
856872
// Pointer aliases need the full `str_intp` path so nil formatting stays
857873
// consistent with plain pointer interpolation.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
return builtin__int_str(n);
2-
builtin__string_plus_many(3, _MOV((string[3]){prefix, builtin__int_str(n), suffix}))
3-
builtin__string_plus_many(4, _MOV((string[4]){_S("n="), builtin__int_str(n), _S(":"), suffix}))
1+
return builtin__str_intp(2, _MOV((StrIntpData[]){{_SLIT0, 0xfe07, {.d_i32 = n}, 0, 0, 0}, {_SLIT0, 0, { .d_c = 0 }, 0, 0, 0}}));
2+
return builtin__str_intp(4, _MOV((StrIntpData[]){{_SLIT0, 0xfe10, {.d_s = prefix}, 0, 0, 0}, {_SLIT0, 0xfe07, {.d_i32 = n}, 0, 0, 0}, {_SLIT0, 0xfe10, {.d_s = suffix}, 0, 0, 0}, {_SLIT0, 0, { .d_c = 0 }, 0, 0, 0}}));
3+
return builtin__str_intp(3, _MOV((StrIntpData[]){{_S("n="), 0xfe07, {.d_i32 = n}, 0, 0, 0}, {_S(":"), 0xfe10, {.d_s = suffix}, 0, 0, 0}, {_SLIT0, 0, { .d_c = 0 }, 0, 0, 0}}));

vlib/v/markused/walker.v

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module markused
66
// Unused functions can be safely skipped by the backends to save CPU time and space.
77
import v.ast
88
import v.pref
9+
import v.util
910

1011
const simple_string_interpolation_default_precision = 987698
1112

@@ -48,6 +49,7 @@ mut:
4849
all_structs map[string]ast.StructDecl
4950

5051
cur_fn string
52+
cur_mod string
5153
cur_fn_concrete_types []ast.Type
5254
level int
5355
is_builtin_mod bool
@@ -1387,12 +1389,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
13871389
w.mark_by_type(node.typ)
13881390
}
13891391
ast.StringInterLiteral {
1390-
if w.string_inter_literal_needs_runtime(node) {
1391-
w.uses_interp = true
1392-
w.uses_interp_isnil = w.uses_interp_isnil || w.string_inter_literal_uses_isnil(node)
1393-
} else {
1394-
w.mark_simple_string_inter_literal(node)
1395-
}
1392+
w.mark_string_inter_literal(node)
13961393
w.exprs(node.exprs)
13971394
for expr in node.fwidth_exprs {
13981395
if expr !is ast.EmptyExpr {
@@ -1585,9 +1582,11 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type
15851582
w.is_direct_array_access = node.is_direct_arr || w.pref.no_bounds_checking
15861583
defer { w.is_direct_array_access = last_is_direct_array_access }
15871584
last_cur_fn := w.cur_fn
1585+
last_cur_mod := w.cur_mod
15881586
last_cur_fn_concrete_types := w.cur_fn_concrete_types.clone()
15891587
defer {
15901588
w.cur_fn = last_cur_fn
1589+
w.cur_mod = last_cur_mod
15911590
w.cur_fn_concrete_types = last_cur_fn_concrete_types
15921591
}
15931592
if w.trace_enabled {
@@ -1657,7 +1656,9 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type
16571656
}
16581657
}
16591658
prev_cur_fn := w.cur_fn
1659+
prev_cur_mod := w.cur_mod
16601660
w.cur_fn = fkey
1661+
w.cur_mod = node.mod
16611662
w.cur_fn_concrete_types = resolved_concrete_types
16621663
if node.mod == 'x.json2' && node.name == 'get_decoded_sumtype_workaround'
16631664
&& w.has_sumtype_generic_context(resolved_concrete_types) {
@@ -1772,6 +1773,7 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type
17721773
w.stmts(node.stmts)
17731774
w.defer_stmts(node.defer_stmts)
17741775
w.cur_fn = prev_cur_fn
1776+
w.cur_mod = prev_cur_mod
17751777
}
17761778

17771779
fn (mut w Walker) fn_decl_with_fkey(mut node ast.FnDecl, walk_fkey string) {
@@ -2715,6 +2717,15 @@ fn (w &Walker) infer_expr_type(expr ast.Expr) ast.Type {
27152717
}
27162718
}
27172719

2720+
fn (mut w Walker) mark_string_inter_literal(node ast.StringInterLiteral) {
2721+
if w.string_inter_literal_needs_runtime(node) {
2722+
w.uses_interp = true
2723+
w.uses_interp_isnil = w.uses_interp_isnil || w.string_inter_literal_uses_isnil(node)
2724+
} else {
2725+
w.mark_simple_string_inter_literal(node)
2726+
}
2727+
}
2728+
27182729
fn (mut w Walker) string_inter_literal_needs_runtime(node ast.StringInterLiteral) bool {
27192730
if w.pref.autofree || w.pref.gc_mode == .boehm_leak {
27202731
return true
@@ -2736,6 +2747,9 @@ fn (mut w Walker) string_inter_literal_needs_runtime(node ast.StringInterLiteral
27362747
if typ == 0 || typ == ast.void_type || typ.has_flag(.generic) {
27372748
return true
27382749
}
2750+
if w.simple_string_interpolation_type_needs_runtime(typ) {
2751+
return true
2752+
}
27392753
normalized_expr_type := w.table.fully_unaliased_type(typ)
27402754
if normalized_expr_type.is_any_kind_of_pointer() || normalized_expr_type.is_int_valptr()
27412755
|| normalized_expr_type.is_float_valptr() {
@@ -2776,6 +2790,19 @@ fn (mut w Walker) string_inter_literal_needs_runtime(node ast.StringInterLiteral
27762790
return false
27772791
}
27782792

2793+
fn (w &Walker) simple_string_interpolation_type_needs_runtime(typ ast.Type) bool {
2794+
if util.module_is_builtin(w.cur_mod) {
2795+
return false
2796+
}
2797+
if typ.has_option_or_result() {
2798+
return false
2799+
}
2800+
resolved_typ := typ.clear_flags()
2801+
return resolved_typ in [ast.i8_type, ast.i16_type, ast.i32_type, ast.int_type, ast.i64_type,
2802+
ast.isize_type, ast.u8_type, ast.u16_type, ast.u32_type, ast.u64_type, ast.usize_type,
2803+
ast.int_literal_type]
2804+
}
2805+
27792806
fn (mut w Walker) string_inter_literal_uses_isnil(node ast.StringInterLiteral) bool {
27802807
for typ in node.expr_types {
27812808
resolved_typ := w.table.fully_unaliased_type(w.resolve_current_generic_type(typ))
@@ -3549,6 +3576,7 @@ fn (mut w Walker) mark_generic_body_dependencies_in_expr(expr_ ast.Expr) {
35493576
w.mark_generic_body_dependencies_in_expr(expr.right)
35503577
}
35513578
ast.StringInterLiteral {
3579+
w.mark_string_inter_literal(expr)
35523580
for sub_expr in expr.exprs {
35533581
w.mark_generic_body_dependencies_in_expr(sub_expr)
35543582
}
@@ -3628,7 +3656,7 @@ fn (mut w Walker) mark_resource_dependencies() {
36283656
if w.uses_interp_isnil || w.auto_str_needs_isnil() {
36293657
w.fn_by_name('isnil')
36303658
}
3631-
if w.auto_str_needs_str_intp() {
3659+
if w.uses_interp || w.auto_str_needs_str_intp() {
36323660
w.fn_by_name('str_intp')
36333661
w.mark_by_sym_name('StrIntpData')
36343662
w.mark_by_sym_name('StrIntpMem')

0 commit comments

Comments
 (0)