gen: support returning large types from closures on amd64 (#12926)
parent
7b4d83660a
commit
cfb814a0e3
|
@ -457,6 +457,9 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) {
|
|||
for param in node.decl.params {
|
||||
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')
|
||||
args_size := size_sb.str()
|
||||
g.writeln('')
|
||||
|
|
|
@ -7,6 +7,58 @@ const (
|
|||
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`
|
||||
// and parameters of type `typ`, to makes sure that all combinations work correctly
|
||||
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,
|
||||
// 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 i in 0 .. max_params {
|
||||
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
|
||||
// a pointer to the entire closure context as their last argument anyways
|
||||
v_code.writeln("
|
||||
fn test_big_closure_${typ}_${i}() {
|
||||
println('test_big_closure_${typ}_$i')
|
||||
mut z := $init_val
|
||||
c := fn [z] (${params.join(', ')}) $return_type {
|
||||
mut sum := z")
|
||||
fn test_big_closure_${typ}_${i}() {
|
||||
println('test_big_closure_${typ}_$i')
|
||||
mut local := 123
|
||||
mut local_2 := 234
|
||||
mut z := $init_val
|
||||
c := fn [z] (${params.join(', ')}) $return_type {
|
||||
mut sum := z")
|
||||
for j in 0 .. i {
|
||||
v_code.writeln('\t\tsum += ${return_type}(${param_names[j]})')
|
||||
}
|
||||
v_code.writeln('
|
||||
return sum
|
||||
v_code.writeln("
|
||||
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')
|
||||
os.mkdir_all(wrkdir) ?
|
||||
os.chdir(wrkdir) ?
|
||||
os.write_file('closure_args_test.v', code) ?
|
||||
os.write_file('closure_return_test.v', code) ?
|
||||
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 {
|
||||
eprintln(res.output)
|
||||
assert false
|
||||
|
|
Loading…
Reference in New Issue