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