@@ -587,7 +587,7 @@ fn (mut b Builder) ssa_type_from_checker_type(typ types.Type) TypeID {
587587 return b.array_type
588588 }
589589 if typ is types.ArrayFixed {
590- return b.m.type_store.get_ptr (b.ssa_type_from_checker_type(typ.elem_type))
590+ return b.m.type_store.get_array (b.ssa_type_from_checker_type(typ.elem_type), typ.len )
591591 }
592592 if typ is types.Map {
593593 return b.map_type
@@ -1182,7 +1182,9 @@ fn (mut b Builder) register_functions() {
11821182 b.register_printing_stubs()
11831183 b.register_at_exit_stub()
11841184 b.register_rand_prng_interface_stubs()
1185+ b.register_embed_file_interface_stubs()
11851186 b.register_pthread_compat_stubs()
1187+ b.register_closure_once_stub()
11861188 b.register_prealloc_allocator_stubs()
11871189 b.register_prealloc_atomic_stubs()
11881190 b.register_atomic_builtin_stubs()
@@ -2492,6 +2494,98 @@ fn (mut b Builder) register_array_runtime_stubs() {
24922494 array_repeat_id := b.register_synthetic_function('array.repeat_to_depth', b.array_type,
24932495 p3_repeat)
24942496 b.generate_array_repeat_to_depth_body(array_repeat_id)
2497+
2498+ for sort_type in ['int', 'i8', 'i16', 'i64', 'u8', 'u16', 'u32', 'u64', 'isize', 'usize', 'f32',
2499+ 'f64', 'rune', 'char'] {
2500+ elem_type := match sort_type {
2501+ 'int', 'rune' { b.i32_type }
2502+ 'i8' { b.i8_type }
2503+ 'i16' { b.m.type_store.get_int(16) }
2504+ 'i64', 'isize' { b.i64_type }
2505+ 'u8', 'char' { b.u8_type }
2506+ 'u16' { b.u16_type }
2507+ 'u32' { b.u32_type }
2508+ 'u64', 'usize' { b.u64_type }
2509+ 'f32' { b.f32_type }
2510+ else { b.f64_type }
2511+ }
2512+ mut sort_params := []TypeID{}
2513+ sort_params << ptr_array
2514+ sort_id := b.register_synthetic_function('v3_array_sort_${sort_type}', b.void_type,
2515+ sort_params)
2516+ b.generate_scalar_array_sort_body(sort_id, elem_type)
2517+ }
2518+ }
2519+
2520+ // generate_scalar_array_sort_body emits the native equivalent of the scalar qsort helpers
2521+ // generated by the C backend.
2522+ fn (mut b Builder) generate_scalar_array_sort_body(func_id int, elem_type TypeID) {
2523+ ptr_i8 := b.m.type_store.get_ptr(b.i8_type)
2524+ ptr_i64 := b.m.type_store.get_ptr(b.i64_type)
2525+ ptr_array := b.m.type_store.get_ptr(b.array_type)
2526+ ptr_elem := b.m.type_store.get_ptr(elem_type)
2527+ entry := b.m.add_block(func_id, 'entry')
2528+ arr := b.func_add_argument(func_id, ptr_array, 'arr')
2529+ i_slot := b.block_instr0(.alloca, entry, ptr_i64)
2530+ j_slot := b.block_instr0(.alloca, entry, ptr_i64)
2531+ data_ptr := b.block_struct_field_ptr(entry, arr, b.array_type, 0)
2532+ data := b.block_instr1(.load, entry, ptr_i8, data_ptr)
2533+ len := b.block_load_array_int_field(entry, arr, 2)
2534+ zero := b.m.get_or_add_const(b.i64_type, '0')
2535+ one := b.m.get_or_add_const(b.i64_type, '1')
2536+ elem_size := b.m.get_or_add_const(b.i64_type, '${b.m.type_size(elem_type)}')
2537+ has_multiple := b.block_instr2(.gt, entry, b.i1_type, len, one)
2538+ outer_init := b.m.add_block(func_id, 'sort_outer_init')
2539+ outer_check := b.m.add_block(func_id, 'sort_outer_check')
2540+ inner_init := b.m.add_block(func_id, 'sort_inner_init')
2541+ inner_check := b.m.add_block(func_id, 'sort_inner_check')
2542+ compare := b.m.add_block(func_id, 'sort_compare')
2543+ swap := b.m.add_block(func_id, 'sort_swap')
2544+ inner_next := b.m.add_block(func_id, 'sort_inner_next')
2545+ outer_next := b.m.add_block(func_id, 'sort_outer_next')
2546+ done := b.m.add_block(func_id, 'sort_done')
2547+ b.block_instr3(.br, entry, b.void_type, has_multiple, ValueID(outer_init), ValueID(done))
2548+
2549+ b.block_instr2(.store, outer_init, b.void_type, zero, i_slot)
2550+ b.block_instr1(.jmp, outer_init, b.void_type, ValueID(outer_check))
2551+
2552+ i := b.block_instr1(.load, outer_check, b.i64_type, i_slot)
2553+ last := b.block_instr2(.sub, outer_check, b.i64_type, len, one)
2554+ has_outer := b.block_instr2(.lt, outer_check, b.i1_type, i, last)
2555+ b.block_instr3(.br, outer_check, b.void_type, has_outer, ValueID(inner_init), ValueID(done))
2556+
2557+ b.block_instr2(.store, inner_init, b.void_type, one, j_slot)
2558+ b.block_instr1(.jmp, inner_init, b.void_type, ValueID(inner_check))
2559+
2560+ j := b.block_instr1(.load, inner_check, b.i64_type, j_slot)
2561+ remaining := b.block_instr2(.sub, inner_check, b.i64_type, len, i)
2562+ has_inner := b.block_instr2(.lt, inner_check, b.i1_type, j, remaining)
2563+ b.block_instr3(.br, inner_check, b.void_type, has_inner, ValueID(compare), ValueID(outer_next))
2564+
2565+ prev_idx := b.block_instr2(.sub, compare, b.i64_type, j, one)
2566+ cur_offset := b.block_instr2(.mul, compare, b.i64_type, j, elem_size)
2567+ prev_offset := b.block_instr2(.mul, compare, b.i64_type, prev_idx, elem_size)
2568+ cur_ptr := b.block_instr2(.get_element_ptr, compare, ptr_elem, data, cur_offset)
2569+ prev_ptr := b.block_instr2(.get_element_ptr, compare, ptr_elem, data, prev_offset)
2570+ cur := b.block_instr1(.load, compare, elem_type, cur_ptr)
2571+ prev := b.block_instr1(.load, compare, elem_type, prev_ptr)
2572+ less_op := if b.is_unsigned_type(elem_type) { OpCode.ult } else { OpCode.lt }
2573+ less := b.block_instr2(less_op, compare, b.i1_type, cur, prev)
2574+ b.block_instr3(.br, compare, b.void_type, less, ValueID(swap), ValueID(inner_next))
2575+
2576+ b.block_instr2(.store, swap, b.void_type, cur, prev_ptr)
2577+ b.block_instr2(.store, swap, b.void_type, prev, cur_ptr)
2578+ b.block_instr1(.jmp, swap, b.void_type, ValueID(inner_next))
2579+
2580+ next_j := b.block_instr2(.add, inner_next, b.i64_type, j, one)
2581+ b.block_instr2(.store, inner_next, b.void_type, next_j, j_slot)
2582+ b.block_instr1(.jmp, inner_next, b.void_type, ValueID(inner_check))
2583+
2584+ next_i := b.block_instr2(.add, outer_next, b.i64_type, i, one)
2585+ b.block_instr2(.store, outer_next, b.void_type, next_i, i_slot)
2586+ b.block_instr1(.jmp, outer_next, b.void_type, ValueID(outer_check))
2587+
2588+ b.block_instr0(.ret, done, b.void_type)
24952589}
24962590
24972591// register_panic_stub updates register panic stub state for ssa.
@@ -3993,6 +4087,8 @@ fn (mut b Builder) generate_at_exit_body(func_id int, result_type TypeID, params
39934087
39944088fn (mut b Builder) register_pthread_compat_stubs() {
39954089 ptr_i8 := b.m.type_store.get_ptr(b.i8_type)
4090+ zero_id := b.register_synthetic_c_function('v3_pthread_zero', b.u64_type, []TypeID{})
4091+ b.generate_const_body_with_params(zero_id, b.u64_type, '0', []TypeID{})
39964092 mut p_create := []TypeID{}
39974093 p_create << ptr_i8
39984094 p_create << b.i64_type
@@ -4008,6 +4104,24 @@ fn (mut b Builder) register_pthread_compat_stubs() {
40084104 b.generate_const_body_with_params(setkind_id, b.i32_type, '0', p_setkind)
40094105}
40104106
4107+ fn (mut b Builder) register_closure_once_stub() {
4108+ callback_type := b.m.type_store.get_ptr(b.i8_type)
4109+ params := [callback_type]
4110+ func_id := b.register_synthetic_c_function('v_closure_init_once', b.void_type, params)
4111+ once_flag := b.m.add_global('v3_closure_init_once_done', b.i1_type)
4112+ entry := b.m.add_block(func_id, 'closure_once_entry')
4113+ callback := b.func_add_argument(func_id, callback_type, 'init_fn')
4114+ done := b.block_instr1(.load, entry, b.i1_type, once_flag)
4115+ call_init := b.m.add_block(func_id, 'closure_once_call')
4116+ return_block := b.m.add_block(func_id, 'closure_once_return')
4117+ b.block_instr3(.br, entry, b.void_type, done, ValueID(return_block), ValueID(call_init))
4118+ true_value := b.m.get_or_add_const(b.i1_type, '1')
4119+ b.block_instr2(.store, call_init, b.void_type, true_value, once_flag)
4120+ b.block_instr1(.call_indirect, call_init, b.void_type, callback)
4121+ b.block_instr1(.jmp, call_init, b.void_type, ValueID(return_block))
4122+ b.block_instr0(.ret, return_block, b.void_type)
4123+ }
4124+
40114125fn (mut b Builder) register_rand_prng_interface_stubs() {
40124126 ptr_i8 := b.m.type_store.get_ptr(b.i8_type)
40134127 mut p_recv := []TypeID{}
@@ -4053,6 +4167,20 @@ fn (mut b Builder) register_rand_prng_interface_stubs() {
40534167 }
40544168}
40554169
4170+ fn (mut b Builder) register_embed_file_interface_stubs() {
4171+ result_type := b.option_type_id('[]u8')
4172+ mut params := []TypeID{}
4173+ params << b.resolve_type('embed_file.Decoder')
4174+ params << b.array_type
4175+ func_id := b.register_synthetic_function('embed_file.Decoder.decompress', result_type, params)
4176+ entry := b.m.add_block(func_id, 'decompress_entry')
4177+ for i, param_type in params {
4178+ _ := b.func_add_argument(func_id, param_type, 'arg${i}')
4179+ }
4180+ result := b.block_option_value(entry, result_type, true, ValueID(0))
4181+ b.block_instr1(.ret, entry, b.void_type, result)
4182+ }
4183+
40564184fn (mut b Builder) generate_noop_body(func_id int, params []TypeID) {
40574185 entry := b.m.add_block(func_id, 'noop_entry')
40584186 for i, param_type in params {
@@ -10121,7 +10249,13 @@ fn (mut b Builder) build_indirect_call(id flat.NodeId, node flat.Node, callee_id
1012110249
1012210250fn (b &Builder) is_function_value_expr(id flat.NodeId) bool {
1012310251 typ := b.checked_expr_type_name(id).trim_space()
10124- return typ.starts_with('fn(') || typ.starts_with('fn (')
10252+ if typ.starts_with('fn(') || typ.starts_with('fn (') {
10253+ return true
10254+ }
10255+ if b.tc != unsafe { nil } && typ.len > 0 && typ != 'unknown' {
10256+ return types.unalias_type(b.tc.parse_type(typ)) is types.FnType
10257+ }
10258+ return false
1012510259}
1012610260
1012710261fn (mut b Builder) call_expr_result_type(id flat.NodeId, node flat.Node) TypeID {
0 commit comments