authorgravatar for ben@happyspork.comBen Anderman <ben@happyspork.com> 2026-08-20 01:22:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-26 20:54:49-07:00
logfb6cce8cf3f2977d1828cff4aa3a9cb1b6ff6b5f
treeb9dd12d84c90e412ceed0dcf18aa346625f47431
parent3cd05f8a1b6fdb39f0ad5aaea4665af908c7840a

Update spork8 backend to modern internal compiler APIs


5 files changed, 166 insertions(+), 65 deletions(-)

src/codegen.zig+4
......@@ -80,6 +80,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
8080 .stage2_x86,
8181 .stage2_riscv64,
8282 .stage2_sparc64,
83 .stage2_spork8,
8384 .stage2_spirv,
8485 => |backend| {
8586 dev.check(devFeatureForBackend(backend));
......@@ -121,6 +122,7 @@ pub const AnyMir = union {
121122 .stage2_wasm => "wasm",
122123 .stage2_c => "c",
123124 .stage2_spirv => "spirv",
125 .stage2_spork8 => "spork8",
124126 else => unreachable,
125127 };
126128 }
......@@ -138,6 +140,7 @@ pub const AnyMir = union {
138140 .stage2_wasm,
139141 .stage2_c,
140142 .stage2_spirv,
143 .stage2_spork8,
141144 => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa),
142145 }
143146 }
......@@ -167,6 +170,7 @@ pub fn generateFunction(
167170 .stage2_x86_64,
168171 .stage2_wasm,
169172 .stage2_c,
173 .stage2_spork8,
170174 .stage2_spirv,
171175 => |backend| {
172176 dev.check(devFeatureForBackend(backend));
src/codegen/spork8/CodeGen.zig+152-60
......@@ -14,87 +14,163 @@ const Mir = @import("Mir.zig");
1414air: Air,
1515liveness: Liveness,
1616gpa: Allocator,
17spork8: *Spork8,
1817pt: Zcu.PerThread,
1918owner_nav: InternPool.Nav.Index,
2019func_index: InternPool.Index,
21mir_instructions: *std.MultiArrayList(Mir.Inst),
20mir_instructions: std.MultiArrayList(Mir.Inst),
2221/// Contains extra data for MIR
23mir_extra: *std.ArrayListUnmanaged(u32),
24start_mir_extra_off: u32,
25
26pub const Error = error{
27 OutOfMemory,
28 /// Compiler was asked to operate on a number larger than supported.
29 Overflow,
30 /// Indicates the error is already stored in Zcu `failed_codegen`.
31 CodegenFail,
32};
33
34pub const Function = extern struct {
35 /// Index into `Spork8.mir_instructions`.
36 mir_off: u32,
37 /// This is unused except for as a safety slice bound and could be removed.
38 mir_len: u32,
39 /// Index into `Spork8.mir_extra`.
40 mir_extra_off: u32,
41 /// This is unused except for as a safety slice bound and could be removed.
42 mir_extra_len: u32,
43};
22mir_extra: std.ArrayListUnmanaged(u32),
23
24pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
25 return comptime &.initMany(&.{
26 .expand_bit_cast_safe,
27 .expand_int_cast_safe,
28 .expand_int_from_float_safe,
29 .expand_int_from_float_optimized_safe,
30 .expand_add_safe,
31 .expand_sub_safe,
32 .expand_mul_safe,
33
34 .expand_packed_load,
35 .expand_packed_store,
36 .expand_packed_agg_field_val,
37 .expand_packed_aggregate_init,
38 .expand_array_to_vector,
39
40 .scalarize_add,
41 .scalarize_add_optimized,
42 .scalarize_add_wrap,
43 .scalarize_add_sat,
44 .scalarize_sub,
45 .scalarize_sub_optimized,
46 .scalarize_sub_wrap,
47 .scalarize_sub_sat,
48 .scalarize_mul,
49 .scalarize_mul_optimized,
50 .scalarize_mul_wrap,
51 .scalarize_mul_sat,
52 .scalarize_div_float,
53 .scalarize_div_float_optimized,
54 .scalarize_div_trunc,
55 .scalarize_div_trunc_optimized,
56 .scalarize_div_floor,
57 .scalarize_div_floor_optimized,
58 .scalarize_div_ceil,
59 .scalarize_div_ceil_optimized,
60 .scalarize_div_exact,
61 .scalarize_div_exact_optimized,
62 .scalarize_rem,
63 .scalarize_rem_optimized,
64 .scalarize_mod,
65 .scalarize_mod_optimized,
66 .scalarize_max,
67 .scalarize_min,
68 .scalarize_add_with_overflow,
69 .scalarize_sub_with_overflow,
70 .scalarize_mul_with_overflow,
71 .scalarize_shl_with_overflow,
72 .scalarize_bit_and,
73 .scalarize_bit_or,
74 .scalarize_shr,
75 .scalarize_shr_exact,
76 .scalarize_shl,
77 .scalarize_shl_exact,
78 .scalarize_shl_sat,
79 .scalarize_xor,
80 .scalarize_not,
81 .scalarize_clz,
82 .scalarize_ctz,
83 .scalarize_popcount,
84 .scalarize_byte_swap,
85 .scalarize_bit_reverse,
86 .scalarize_sqrt,
87 .scalarize_sin,
88 .scalarize_cos,
89 .scalarize_tan,
90 .scalarize_exp,
91 .scalarize_exp2,
92 .scalarize_log,
93 .scalarize_log2,
94 .scalarize_log10,
95 .scalarize_abs,
96 .scalarize_floor,
97 .scalarize_ceil,
98 .scalarize_round,
99 .scalarize_trunc_float,
100 .scalarize_neg,
101 .scalarize_neg_optimized,
102 .scalarize_cmp_vector,
103 .scalarize_cmp_vector_optimized,
104 .scalarize_fptrunc,
105 .scalarize_fpext,
106 .scalarize_int_cast,
107 .scalarize_ptr_cast,
108 .scalarize_ptr_from_int,
109 .scalarize_int_from_ptr,
110 .scalarize_trunc,
111 .scalarize_int_from_float,
112 .scalarize_int_from_float_optimized,
113 .scalarize_float_from_int,
114 .scalarize_reduce,
115 .scalarize_reduce_optimized,
116 .scalarize_shuffle_one,
117 .scalarize_shuffle_two,
118 .scalarize_select,
119 .scalarize_mul_add,
120
121 .scalarize_bit_cast_padded_elems,
122 });
123}
44124
45pub fn function(
46 spork8: *Spork8,
125pub fn generate(
126 bin_file: *link.File,
47127 pt: Zcu.PerThread,
48128 func_index: InternPool.Index,
49 air: Air,
50 liveness: Liveness,
51) Error!Function {
129 air: *const Air,
130 liveness: *const ?Air.Liveness,
131) link.Error!Mir {
132 _ = bin_file;
52133 const zcu = pt.zcu;
53134 const gpa = zcu.gpa;
54 const func_info = zcu.funcInfo(func_index);
135 const cg = zcu.funcInfo(func_index);
55136
56137 var code_gen: CodeGen = .{
57138 .gpa = gpa,
58139 .pt = pt,
59 .air = air,
60 .liveness = liveness,
61 .owner_nav = func_info.owner_nav,
62 .spork8 = spork8,
140 .air = air.*,
141 .liveness = liveness.*.?,
142 .owner_nav = cg.owner_nav,
63143 .func_index = func_index,
64 .mir_instructions = &spork8.mir_instructions,
65 .mir_extra = &spork8.mir_extra,
66 .start_mir_extra_off = @intCast(spork8.mir_extra.items.len),
144 .mir_instructions = .empty,
145 .mir_extra = .empty,
67146 };
68147 defer code_gen.deinit();
69148
70 return functionInner(&code_gen) catch |err| switch (err) {
71 error.CodegenFail => return error.CodegenFail,
72 else => |e| return code_gen.fail("failed to generate function: {s}", .{@errorName(e)}),
149 return generateInner(&code_gen) catch |err| switch (err) {
150 error.AlreadyReported,
151 error.OutOfMemory,
152 => |e| return e,
73153 };
74154}
75155
76fn deinit(cg: *CodeGen) void {
156pub fn deinit(cg: *CodeGen) void {
77157 cg.* = undefined;
78158}
79159
80160const InnerError = error{
81 CodegenFail,
161 AlreadyReported,
82162 OutOfMemory,
83163};
84164
85fn functionInner(cg: *CodeGen) InnerError!Function {
86 const spork8 = cg.spork8;
87
88 const start_mir_off: u32 = @intCast(spork8.mir_instructions.len);
89
165fn generateInner(cg: *CodeGen) InnerError!Mir {
90166 // Generate MIR for function body
91167 try cg.genBody(cg.air.getMainBody());
92168
169 try cg.mir_extra.shrinkToLen(cg.gpa);
170
93171 return .{
94 .mir_off = start_mir_off,
95 .mir_len = @intCast(spork8.mir_instructions.len - start_mir_off),
96 .mir_extra_off = cg.start_mir_extra_off,
97 .mir_extra_len = cg.extraLen(),
172 .instructions = cg.mir_instructions.toOwnedSlice(),
173 .extra = cg.mir_extra.toOwnedSliceAssert(),
98174 };
99175}
100176
......@@ -130,8 +206,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
130206 .div_floor,
131207 .bit_and,
132208 .bit_or,
133 .bool_and,
134 .bool_or,
135209 .rem,
136210 .mod,
137211 .shl,
......@@ -177,13 +251,11 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
177251 .cmp_neq,
178252
179253 .cmp_vector,
180 .cmp_lt_errors_len,
181254
182255 .array_elem_val,
183256 .array_to_slice,
184257 .alloc,
185258 .arg,
186 .bitcast,
187259 .block,
188260 .trap,
189261 .breakpoint,
......@@ -191,7 +263,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
191263 .repeat,
192264 .switch_dispatch,
193265 .cond_br,
194 .intcast,
195266 .fptrunc,
196267 .fpext,
197268 .int_from_float,
......@@ -241,7 +312,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
241312 .ret_load,
242313 .splat,
243314 .select,
244 .shuffle,
245315 .reduce,
246316 .aggregate_init,
247317 .union_init,
......@@ -266,7 +336,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
266336 .struct_field_ptr_index_1,
267337 .struct_field_ptr_index_2,
268338 .struct_field_ptr_index_3,
269 .struct_field_val,
270339 .field_parent_ptr,
271340
272341 .switch_br,
......@@ -303,7 +372,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
303372 .save_err_return_trace_index,
304373 .is_named_enum_value,
305374 .addrspace_cast,
306 .vector_store_elem,
307375 .c_va_arg,
308376 .c_va_copy,
309377 .c_va_end,
......@@ -341,7 +409,31 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
341409 .add_safe,
342410 .sub_safe,
343411 .mul_safe,
344 .intcast_safe,
412 .div_ceil,
413 .div_ceil_optimized,
414 .bit_cast,
415 .bit_cast_safe,
416 .ptr_cast,
417 .ptr_from_int,
418 .int_from_ptr,
419 .error_cast,
420 .error_from_int,
421 .int_from_error,
422 .union_from_enum,
423 .int_cast,
424 .int_cast_safe,
425 .agg_field_val,
426 .array_to_vector,
427 .int_from_float_safe,
428 .int_from_float_optimized_safe,
429 .shuffle_one,
430 .shuffle_two,
431 .cmp_lte_errors_len,
432 .runtime_nav_ptr,
433 .spirv_runtime_array_len,
434 .legalize_vec_store_elem,
435 .legalize_vec_elem_val,
436 .legalize_compiler_rt_call,
345437 => |tag| return cg.fail("TODO: implement spork8 inst: {s}", .{@tagName(tag)}),
346438
347439 .work_item_id,
......@@ -356,7 +448,7 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
356448 _ = inst;
357449}
358450
359fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
451fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {
360452 const zcu = cg.pt.zcu;
361453 const func = zcu.funcInfo(cg.func_index);
362454 return zcu.codegenFail(func.owner_nav, fmt, args);
src/codegen/spork8/Mir.zig+9-4
......@@ -5,8 +5,8 @@ const builtin = @import("builtin");
55const std = @import("std");
66const assert = std.debug.assert;
77
8instruction_tags: []const Inst.Tag,
9instruction_datas: []const Inst.Data,
8instructions: std.MultiArrayList(Inst).Slice,
9
1010extra: []const u32,
1111
1212pub const Inst = struct {
......@@ -24,9 +24,9 @@ pub const Inst = struct {
2424 /// imm8
2525 set_addr_i = 0x09,
2626 /// imm8
27 load_i = 0x10,
27 load_i = 0x11,
2828 /// index
29 jump,
29 jump = 0x68,
3030 };
3131
3232 /// All instructions contain a 4-byte payload, which is contained within
......@@ -44,3 +44,8 @@ pub const Inst = struct {
4444 }
4545 };
4646};
47
48pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
49 mir.instructions.deinit(gpa);
50 mir.* = undefined;
51}
src/dev.zig+1
......@@ -248,6 +248,7 @@ pub const Env = enum {
248248 .spork8 => switch (feature) {
249249 .stdio_listen,
250250 .incremental,
251 .legalize,
251252 .spork8_backend,
252253 .spork8_linker,
253254 => true,
src/link/Spork8.zig-1
......@@ -22,7 +22,6 @@ const dev = @import("../dev.zig");
2222const Value = @import("../Value.zig");
2323
2424base: link.File,
25funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, CodeGen.Function) = .empty,
2625/// All MIR instructions for all Zcu functions.
2726mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
2827/// Corresponds to `mir_instructions`.