gen: support returning large types from closures on amd64 (#12926)
parent
7b4d83660a
commit
cfb814a0e3
vlib/v
gen/c
|
@ -457,6 +457,9 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) {
|
||||||
for param in node.decl.params {
|
for param in node.decl.params {
|
||||||
size_sb.write_string('_REG_WIDTH(${g.typ(param.typ)}) + ')
|
size_sb.write_string('_REG_WIDTH(${g.typ(param.typ)}) + ')
|
||||||
}
|
}
|
||||||
|
if g.pref.arch == .amd64 && node.decl.return_type != ast.void_type {
|
||||||
|
size_sb.write_string('(_REG_WIDTH(${g.typ(node.decl.return_type)}) > 2) + ')
|
||||||
|
}
|
||||||
size_sb.write_string('1')
|
size_sb.write_string('1')
|
||||||
args_size := size_sb.str()
|
args_size := size_sb.str()
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
|
|
|
@ -7,6 +7,58 @@ const (
|
||||||
all_param_values = []string{len: max_params, init: '${it + 1}'}
|
all_param_values = []string{len: max_params, init: '${it + 1}'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
struct ReturnType {
|
||||||
|
name string
|
||||||
|
init string
|
||||||
|
assertion string
|
||||||
|
no_assert_kw bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const return_types = [
|
||||||
|
ReturnType{
|
||||||
|
name: ''
|
||||||
|
init: ''
|
||||||
|
assertion: ''
|
||||||
|
no_assert_kw: true
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: 'int'
|
||||||
|
init: '-123'
|
||||||
|
assertion: ' == -123'
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: 'u64'
|
||||||
|
init: '123'
|
||||||
|
assertion: ' == 123'
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: 'voidptr'
|
||||||
|
init: 'voidptr(123)'
|
||||||
|
assertion: ' == voidptr(123)'
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: 'string'
|
||||||
|
init: "'hello'"
|
||||||
|
assertion: " == 'hello'"
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: '?'
|
||||||
|
init: "error('an error')"
|
||||||
|
assertion: " or { assert err.msg == 'an error' return }\npanic('got no error')"
|
||||||
|
no_assert_kw: true
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: '?string'
|
||||||
|
init: "'hello'"
|
||||||
|
assertion: "? == 'hello'"
|
||||||
|
},
|
||||||
|
ReturnType{
|
||||||
|
name: 'BigStruct'
|
||||||
|
init: 'BigStruct{ a3: 56, a27: 1234, a61: 5555 }'
|
||||||
|
assertion: ' == BigStruct{ a3: 56, a27: 1234, a61: 5555 }'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
// test_closures_with_n_args generates a new V file containing closures of `i`
|
// test_closures_with_n_args generates a new V file containing closures of `i`
|
||||||
// and parameters of type `typ`, to makes sure that all combinations work correctly
|
// and parameters of type `typ`, to makes sure that all combinations work correctly
|
||||||
fn test_closures_with_n_args() ? {
|
fn test_closures_with_n_args() ? {
|
||||||
|
@ -14,6 +66,12 @@ fn test_closures_with_n_args() ? {
|
||||||
// NB: the type or value of the captured arg doesn't matter for this test,
|
// NB: the type or value of the captured arg doesn't matter for this test,
|
||||||
// as the entire closure context is always passed as one pointer anyways
|
// as the entire closure context is always passed as one pointer anyways
|
||||||
|
|
||||||
|
v_code.write_string('struct BigStruct {')
|
||||||
|
for i in 0 .. 64 {
|
||||||
|
v_code.write_string('\ta$i int ')
|
||||||
|
}
|
||||||
|
v_code.writeln('}')
|
||||||
|
|
||||||
for typ in ['byte', 'u16', 'int', 'i64', 'voidptr', 'string'] {
|
for typ in ['byte', 'u16', 'int', 'i64', 'voidptr', 'string'] {
|
||||||
for i in 0 .. max_params {
|
for i in 0 .. max_params {
|
||||||
param_names := all_param_names[..i]
|
param_names := all_param_names[..i]
|
||||||
|
@ -41,19 +99,59 @@ fn test_closures_with_n_args() ? {
|
||||||
// NB: the captured arg doesn't matter for this test, as closures always receive
|
// NB: the captured arg doesn't matter for this test, as closures always receive
|
||||||
// a pointer to the entire closure context as their last argument anyways
|
// a pointer to the entire closure context as their last argument anyways
|
||||||
v_code.writeln("
|
v_code.writeln("
|
||||||
fn test_big_closure_${typ}_${i}() {
|
fn test_big_closure_${typ}_${i}() {
|
||||||
println('test_big_closure_${typ}_$i')
|
println('test_big_closure_${typ}_$i')
|
||||||
mut z := $init_val
|
mut local := 123
|
||||||
c := fn [z] (${params.join(', ')}) $return_type {
|
mut local_2 := 234
|
||||||
mut sum := z")
|
mut z := $init_val
|
||||||
|
c := fn [z] (${params.join(', ')}) $return_type {
|
||||||
|
mut sum := z")
|
||||||
for j in 0 .. i {
|
for j in 0 .. i {
|
||||||
v_code.writeln('\t\tsum += ${return_type}(${param_names[j]})')
|
v_code.writeln('\t\tsum += ${return_type}(${param_names[j]})')
|
||||||
}
|
}
|
||||||
v_code.writeln('
|
v_code.writeln("
|
||||||
return sum
|
return sum
|
||||||
|
}
|
||||||
|
assert c(${values.join(', ')}) == $expected_val
|
||||||
|
// ensure stack wasn't overwritten:
|
||||||
|
assert local == 123
|
||||||
|
assert local_2 == 234
|
||||||
|
}")
|
||||||
}
|
}
|
||||||
assert c(${values.join(', ')}) == $expected_val
|
}
|
||||||
}')
|
|
||||||
|
for return_type in return_types {
|
||||||
|
typ := return_type.name
|
||||||
|
styp := typ.replace('?', 'option_').to_lower()
|
||||||
|
init := return_type.init
|
||||||
|
assertion := return_type.assertion
|
||||||
|
|
||||||
|
for i in 0 .. 10 {
|
||||||
|
param_names := all_param_names[..i]
|
||||||
|
params := param_names.map('$it int')
|
||||||
|
values := all_param_values[..i]
|
||||||
|
|
||||||
|
assert_line := if !return_type.no_assert_kw {
|
||||||
|
'assert c(${values.join(', ')}) $assertion'
|
||||||
|
} else {
|
||||||
|
'c(${values.join(', ')}) $assertion'
|
||||||
|
}
|
||||||
|
// NB: the captured arg doesn't matter for this test, as closures always receive
|
||||||
|
// a pointer to the entire closure context as their last argument anyways
|
||||||
|
v_code.writeln("
|
||||||
|
fn test_closure_return_${styp}_${i}() ? {
|
||||||
|
println('test_closure_return_${styp}_$i')
|
||||||
|
mut local := 123
|
||||||
|
mut local_2 := 234
|
||||||
|
mut z := 1234
|
||||||
|
c := fn [z] (${params.join(', ')}) $typ {
|
||||||
|
return $init
|
||||||
|
}
|
||||||
|
$assert_line
|
||||||
|
// ensure stack wasn't overwritten:
|
||||||
|
assert local == 123
|
||||||
|
assert local_2 == 234
|
||||||
|
}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +160,9 @@ fn test_closures_with_n_args() ? {
|
||||||
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'closures')
|
wrkdir := os.join_path(os.temp_dir(), 'vtests', 'closures')
|
||||||
os.mkdir_all(wrkdir) ?
|
os.mkdir_all(wrkdir) ?
|
||||||
os.chdir(wrkdir) ?
|
os.chdir(wrkdir) ?
|
||||||
os.write_file('closure_args_test.v', code) ?
|
os.write_file('closure_return_test.v', code) ?
|
||||||
vexe := os.getenv('VEXE')
|
vexe := os.getenv('VEXE')
|
||||||
res := os.execute('"$vexe" closure_args_test.v')
|
res := os.execute('"$vexe" -keepc -cg -showcc closure_return_test.v')
|
||||||
if res.exit_code != 0 {
|
if res.exit_code != 0 {
|
||||||
eprintln(res.output)
|
eprintln(res.output)
|
||||||
assert false
|
assert false
|
||||||
|
|
Loading…
Reference in New Issue