authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-05-15 13:11:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-26 20:54:49-07:00
log3cd05f8a1b6fdb39f0ad5aaea4665af908c7840a
tree5f9a8ea5e07ff58aee8f4b05d3863f6e61c3588e
parent896bd9e1538ed9d06ff6b212e3df1da978c7e34e

init spork8 backend


17 files changed, 687 insertions(+), 3 deletions(-)

lib/std/Build/Configuration.zig+2
......@@ -2341,6 +2341,7 @@ pub const TargetQuery = struct {
23412341 sheb,
23422342 sparc,
23432343 sparc64,
2344 spork8,
23442345 spirv32,
23452346 spirv64,
23462347 thumb,
......@@ -2442,6 +2443,7 @@ pub const TargetQuery = struct {
24422443 elf,
24432444 hex,
24442445 macho,
2446 spork8,
24452447 plan9,
24462448 raw,
24472449 spirv,
lib/std/Target.zig+33
......@@ -104,6 +104,7 @@ pub const Os = struct {
104104 .plan9 => arch.plan9Ext(),
105105 else => switch (arch) {
106106 .wasm32, .wasm64 => ".wasm",
107 .spork8 => ".spork8",
107108 else => "",
108109 },
109110 };
......@@ -795,6 +796,24 @@ pub const xcore = @import("Target/xcore.zig");
795796pub const xtensa = @import("Target/xtensa.zig");
796797pub const z80 = @import("Target/generic.zig");
797798
799pub const spork8 = struct {
800 pub const Feature = enum {};
801 pub const featureSet = Cpu.Feature.FeatureSetFns(Feature).featureSet;
802 pub const featureSetHas = Cpu.Feature.FeatureSetFns(Feature).featureSetHas;
803 pub const featureSetHasAny = Cpu.Feature.FeatureSetFns(Feature).featureSetHasAny;
804 pub const featureSetHasAll = Cpu.Feature.FeatureSetFns(Feature).featureSetHasAll;
805
806 pub const cpu = struct {
807 pub const generic: Cpu.Model = .{
808 .name = "generic",
809 .llvm_name = null,
810 .features = .empty,
811 };
812 };
813
814 pub const all_features: [0]Cpu.Feature = .{};
815};
816
798817pub const Abi = enum {
799818 none,
800819 gnu,
......@@ -1046,6 +1065,7 @@ pub const ObjectFormat = enum {
10461065 hex,
10471066 /// The Mach object format used by macOS and other Apple platforms.
10481067 macho,
1068 spork8,
10491069 /// The a.out format used by Plan 9 from Bell Labs.
10501070 plan9,
10511071 /// Machine code with no metadata.
......@@ -1061,6 +1081,7 @@ pub const ObjectFormat = enum {
10611081 .coff => ".obj",
10621082 .elf, .macho, .wasm => ".o",
10631083 .hex => ".ihex",
1084 .spork8 => ".spork8",
10641085 .plan9 => arch.plan9Ext(),
10651086 .raw => ".bin",
10661087 .spirv => ".spv",
......@@ -1075,6 +1096,7 @@ pub const ObjectFormat = enum {
10751096 else => switch (arch) {
10761097 .spirv32, .spirv64 => .spirv,
10771098 .wasm32, .wasm64 => .wasm,
1099 .spork8 => .spork8,
10781100 else => .elf,
10791101 },
10801102 };
......@@ -1124,6 +1146,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
11241146 .spirv64,
11251147 .wasm32,
11261148 .wasm64,
1149 .spork8,
11271150 => .NONE,
11281151 };
11291152}
......@@ -1191,6 +1214,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
11911214 .xcore,
11921215 .xtensa,
11931216 .xtensaeb,
1217 .spork8,
11941218 => .UNKNOWN,
11951219 };
11961220}
......@@ -1395,6 +1419,7 @@ pub const Cpu = struct {
13951419 sheb,
13961420 sparc,
13971421 sparc64,
1422 spork8,
13981423 spirv32,
13991424 spirv64,
14001425 thumb,
......@@ -1447,6 +1472,7 @@ pub const Cpu = struct {
14471472 xcore,
14481473 xtensa,
14491474 z80,
1475 spork8,
14501476 };
14511477
14521478 pub inline fn family(arch: Arch) Family {
......@@ -1485,6 +1511,7 @@ pub const Cpu = struct {
14851511 .x86_16, .x86, .x86_64 => .x86,
14861512 .xcore => .xcore,
14871513 .xtensa, .xtensaeb => .xtensa,
1514 .spork8 => .spork8,
14881515 };
14891516 }
14901517
......@@ -1749,6 +1776,7 @@ pub const Cpu = struct {
17491776 .sparc,
17501777 .sparc64,
17511778 .xtensaeb,
1779 .spork8,
17521780 => .big,
17531781
17541782 // GPU endianness is opaque. For now, assume little endian.
......@@ -2971,6 +2999,7 @@ pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
29712999 .avr,
29723000 .msp430,
29733001 .x86_16,
3002 .spork8,
29743003 => 16,
29753004
29763005 .ez80,
......@@ -3536,6 +3565,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
35363565 switch (target.cpu.arch) {
35373566 .avr,
35383567 .ez80,
3568 .spork8,
35393569 => return 1,
35403570 .x86 => switch (target.os.tag) {
35413571 .windows, .uefi => switch (c_type) {
......@@ -3634,6 +3664,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
36343664
36353665 .avr,
36363666 .ez80,
3667 .spork8,
36373668 => unreachable, // Handled above.
36383669 }),
36393670 );
......@@ -3643,6 +3674,7 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
36433674 return switch (target.cpu.arch) {
36443675 .avr,
36453676 .ez80,
3677 .spork8,
36463678 => 1,
36473679
36483680 .msp430,
......@@ -3788,6 +3820,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
37883820 .nvptx, .nvptx64 => .nvptx_device,
37893821 .spirv32, .spirv64 => .spirv_device,
37903822 .ez80 => .ez80_cet,
3823 .spork8 => .naked,
37913824 };
37923825}
37933826
lib/std/debug.zig+1-1
......@@ -75,7 +75,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {
7575 else => @import("debug/SelfInfo/Elf.zig"),
7676 },
7777 .macho => @import("debug/SelfInfo/MachO.zig"),
78 .plan9, .spirv, .wasm => void,
78 .plan9, .spirv, .wasm, .spork8 => void,
7979 .c, .hex, .raw => unreachable,
8080 };
8181}
lib/std/lang.zig+3
......@@ -1319,6 +1319,9 @@ pub const CompilerBackend = enum(u64) {
13191319 /// The reference implementation self-hosted compiler of Zig, using the
13201320 /// loongarch backend.
13211321 stage2_loongarch = 13,
1322 /// The Zig Software Foundation self-hosted implementation of Zig. Backend
1323 /// originally contributed by Ben Anderman in 2026.
1324 zsf_spork8 = 14,
13221325
13231326 _,
13241327};
lib/std/start.zig+3-1
......@@ -19,7 +19,9 @@ comptime {
1919 // decls there get run.
2020 _ = root;
2121
22 if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) {
22 if (builtin.cpu.arch == .spork8) {
23 // always freestanding, even exes
24 } else if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) {
2325 const dll_main_crt_startup = if (builtin.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup";
2426 if (native_os == .windows and !builtin.link_libc and !@hasDecl(root, dll_main_crt_startup)) {
2527 @export(&DllMainCRTStartup, .{ .name = dll_main_crt_startup });
lib/std/zig.zig+1
......@@ -259,6 +259,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
259259 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
260260 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
261261 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
262 .spork8 => return std.fmt.allocPrint(allocator, "{s}.spork8", .{root_name}),
262263 .plan9 => switch (options.output_mode) {
263264 .Exe => return allocator.dupe(u8, root_name),
264265 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
lib/std/zig/llvm/Builder.zig+2
......@@ -162,6 +162,7 @@ pub fn tripleForTarget(allocator: Allocator, target: *const std.Target) ![]const
162162 .propeller,
163163 .sh,
164164 .sheb,
165 .spork8,
165166 .x86_16,
166167 .xtensaeb,
167168 => unreachable, // Gated by hasLlvmSupport().
......@@ -576,6 +577,7 @@ pub const DataLayout = struct {
576577 .sheb,
577578 .x86_16,
578579 .xtensaeb,
580 .spork8,
579581 => unreachable,
580582 };
581583 }
src/Compilation/Config.zig+1-1
......@@ -501,7 +501,7 @@ pub fn resolve(options: Options) ResolveError!Config {
501501 .windows, .uefi => .code_view,
502502 else => .{ .dwarf = .@"32" },
503503 },
504 .spirv, .hex, .raw, .plan9 => .strip,
504 .spirv, .hex, .raw, .plan9, .spork8 => .strip,
505505 };
506506 };
507507
src/Zcu.zig+5
......@@ -4042,6 +4042,7 @@ pub fn atomicPtrAlignment(
40424042 const target = zcu.getTarget();
40434043 const max_atomic_bits: u16 = switch (target.cpu.arch) {
40444044 .ez80,
4045 .spork8,
40454046 => 8,
40464047
40474048 .aarch64,
......@@ -4697,6 +4698,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46974698 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,
46984699 else => false,
46994700 },
4701 .zsf_spork8 => switch (cc) {
4702 .naked => true,
4703 else => false,
4704 },
47004705 };
47014706 if (!backend_ok) return .{ .bad_backend = backend };
47024707 return .ok;
src/codegen.zig+3
......@@ -38,6 +38,7 @@ fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {
3838 .stage2_powerpc => unreachable,
3939 .stage2_riscv64 => .riscv64_backend,
4040 .stage2_sparc64 => .sparc64_backend,
41 .zsf_spork8 => .spork8_backend,
4142 .stage2_spirv => .spirv_backend,
4243 .stage2_wasm => .wasm_backend,
4344 .stage2_x86 => .x86_backend,
......@@ -58,6 +59,7 @@ fn importBackend(comptime backend: std.lang.CompilerBackend) type {
5859 .stage2_riscv64 => @import("codegen/riscv64/CodeGen.zig"),
5960 .stage2_sparc64 => @import("codegen/sparc64/CodeGen.zig"),
6061 .stage2_spirv => @import("codegen/spirv/CodeGen.zig"),
62 .zsf_spork8 => @import("codegen/spork8/CodeGen.zig"),
6163 .stage2_wasm => @import("codegen/wasm/CodeGen.zig"),
6264 .stage2_x86, .stage2_x86_64 => @import("codegen/x86_64/CodeGen.zig"),
6365 _ => unreachable,
......@@ -107,6 +109,7 @@ pub const AnyMir = union {
107109 wasm: if (dev.env.supports(.wasm_backend)) @import("codegen/wasm/Mir.zig") else noreturn,
108110 c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn,
109111 spirv: if (dev.env.supports(.spirv_backend)) @import("codegen/spirv/Mir.zig") else noreturn,
112 spork8: if (dev.env.supports(.spork8_backend)) @import("codegen/spork8/Mir.zig") else noreturn,
110113
111114 pub inline fn tag(comptime backend: std.lang.CompilerBackend) []const u8 {
112115 return switch (backend) {
src/codegen/llvm.zig+1
......@@ -4720,6 +4720,7 @@ pub fn initializeLLVMTarget(io: Io, arch: std.Target.Cpu.Arch) void {
47204720 .propeller,
47214721 .sh,
47224722 .sheb,
4723 .spork8,
47234724 .x86_16,
47244725 .xtensaeb,
47254726 => unreachable,
src/codegen/spork8/CodeGen.zig created+367
......@@ -0,0 +1,367 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4
5const CodeGen = @This();
6const link = @import("../../link.zig");
7const Spork8 = link.File.Spork8;
8const Zcu = @import("../../Zcu.zig");
9const InternPool = @import("../../InternPool.zig");
10const Air = @import("../../Air.zig");
11const Liveness = Air.Liveness;
12const Mir = @import("Mir.zig");
13
14air: Air,
15liveness: Liveness,
16gpa: Allocator,
17spork8: *Spork8,
18pt: Zcu.PerThread,
19owner_nav: InternPool.Nav.Index,
20func_index: InternPool.Index,
21mir_instructions: *std.MultiArrayList(Mir.Inst),
22/// 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};
44
45pub fn function(
46 spork8: *Spork8,
47 pt: Zcu.PerThread,
48 func_index: InternPool.Index,
49 air: Air,
50 liveness: Liveness,
51) Error!Function {
52 const zcu = pt.zcu;
53 const gpa = zcu.gpa;
54 const func_info = zcu.funcInfo(func_index);
55
56 var code_gen: CodeGen = .{
57 .gpa = gpa,
58 .pt = pt,
59 .air = air,
60 .liveness = liveness,
61 .owner_nav = func_info.owner_nav,
62 .spork8 = spork8,
63 .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),
67 };
68 defer code_gen.deinit();
69
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)}),
73 };
74}
75
76fn deinit(cg: *CodeGen) void {
77 cg.* = undefined;
78}
79
80const InnerError = error{
81 CodegenFail,
82 OutOfMemory,
83};
84
85fn functionInner(cg: *CodeGen) InnerError!Function {
86 const spork8 = cg.spork8;
87
88 const start_mir_off: u32 = @intCast(spork8.mir_instructions.len);
89
90 // Generate MIR for function body
91 try cg.genBody(cg.air.getMainBody());
92
93 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(),
98 };
99}
100
101fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
102 const zcu = cg.pt.zcu;
103 const ip = &zcu.intern_pool;
104
105 for (body) |inst| {
106 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
107 try cg.genInst(inst);
108 }
109}
110
111fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
112 const air_tags = cg.air.instructions.items(.tag);
113 return switch (air_tags[@intFromEnum(inst)]) {
114 .inferred_alloc, .inferred_alloc_comptime => unreachable,
115
116 .unreach => cg.airUnreachable(inst),
117
118 .add,
119 .add_sat,
120 .add_wrap,
121 .sub,
122 .sub_sat,
123 .sub_wrap,
124 .mul,
125 .mul_sat,
126 .mul_wrap,
127 .div_float,
128 .div_exact,
129 .div_trunc,
130 .div_floor,
131 .bit_and,
132 .bit_or,
133 .bool_and,
134 .bool_or,
135 .rem,
136 .mod,
137 .shl,
138 .shl_exact,
139 .shl_sat,
140 .shr,
141 .shr_exact,
142 .xor,
143 .max,
144 .min,
145 .mul_add,
146
147 .sqrt,
148 .sin,
149 .cos,
150 .tan,
151 .exp,
152 .exp2,
153 .log,
154 .log2,
155 .log10,
156 .floor,
157 .ceil,
158 .round,
159 .trunc_float,
160 .neg,
161
162 .abs,
163
164 .add_with_overflow,
165 .sub_with_overflow,
166 .shl_with_overflow,
167 .mul_with_overflow,
168
169 .clz,
170 .ctz,
171
172 .cmp_eq,
173 .cmp_gte,
174 .cmp_gt,
175 .cmp_lte,
176 .cmp_lt,
177 .cmp_neq,
178
179 .cmp_vector,
180 .cmp_lt_errors_len,
181
182 .array_elem_val,
183 .array_to_slice,
184 .alloc,
185 .arg,
186 .bitcast,
187 .block,
188 .trap,
189 .breakpoint,
190 .br,
191 .repeat,
192 .switch_dispatch,
193 .cond_br,
194 .intcast,
195 .fptrunc,
196 .fpext,
197 .int_from_float,
198 .float_from_int,
199 .get_union_tag,
200
201 .@"try",
202 .try_cold,
203 .try_ptr,
204 .try_ptr_cold,
205
206 .dbg_stmt,
207 .dbg_empty_stmt,
208 .dbg_inline_block,
209 .dbg_var_ptr,
210 .dbg_var_val,
211 .dbg_arg_inline,
212
213 .call,
214 .call_always_tail,
215 .call_never_tail,
216 .call_never_inline,
217
218 .is_err,
219 .is_non_err,
220
221 .is_null,
222 .is_non_null,
223 .is_null_ptr,
224 .is_non_null_ptr,
225
226 .load,
227 .loop,
228 .memset,
229 .memset_safe,
230 .not,
231 .optional_payload,
232 .optional_payload_ptr,
233 .optional_payload_ptr_set,
234 .ptr_add,
235 .ptr_sub,
236 .ptr_elem_ptr,
237 .ptr_elem_val,
238 .ret,
239 .ret_safe,
240 .ret_ptr,
241 .ret_load,
242 .splat,
243 .select,
244 .shuffle,
245 .reduce,
246 .aggregate_init,
247 .union_init,
248 .prefetch,
249 .popcount,
250 .byte_swap,
251 .bit_reverse,
252
253 .slice,
254 .slice_len,
255 .slice_elem_val,
256 .slice_elem_ptr,
257 .slice_ptr,
258 .ptr_slice_len_ptr,
259 .ptr_slice_ptr_ptr,
260 .store,
261 .store_safe,
262
263 .set_union_tag,
264 .struct_field_ptr,
265 .struct_field_ptr_index_0,
266 .struct_field_ptr_index_1,
267 .struct_field_ptr_index_2,
268 .struct_field_ptr_index_3,
269 .struct_field_val,
270 .field_parent_ptr,
271
272 .switch_br,
273 .loop_switch_br,
274 .trunc,
275
276 .wrap_optional,
277 .unwrap_errunion_payload,
278 .unwrap_errunion_payload_ptr,
279 .unwrap_errunion_err,
280 .unwrap_errunion_err_ptr,
281 .wrap_errunion_payload,
282 .wrap_errunion_err,
283 .errunion_payload_ptr_set,
284 .error_name,
285
286 .wasm_memory_size,
287 .wasm_memory_grow,
288
289 .memcpy,
290
291 .ret_addr,
292 .tag_name,
293
294 .error_set_has_value,
295 .frame_addr,
296
297 .assembly,
298 .is_err_ptr,
299 .is_non_err_ptr,
300
301 .err_return_trace,
302 .set_err_return_trace,
303 .save_err_return_trace_index,
304 .is_named_enum_value,
305 .addrspace_cast,
306 .vector_store_elem,
307 .c_va_arg,
308 .c_va_copy,
309 .c_va_end,
310 .c_va_start,
311 .memmove,
312
313 .atomic_load,
314 .atomic_store_unordered,
315 .atomic_store_monotonic,
316 .atomic_store_release,
317 .atomic_store_seq_cst,
318 .atomic_rmw,
319 .cmpxchg_weak,
320 .cmpxchg_strong,
321
322 .add_optimized,
323 .sub_optimized,
324 .mul_optimized,
325 .div_float_optimized,
326 .div_trunc_optimized,
327 .div_floor_optimized,
328 .div_exact_optimized,
329 .rem_optimized,
330 .mod_optimized,
331 .neg_optimized,
332 .cmp_lt_optimized,
333 .cmp_lte_optimized,
334 .cmp_eq_optimized,
335 .cmp_gte_optimized,
336 .cmp_gt_optimized,
337 .cmp_neq_optimized,
338 .cmp_vector_optimized,
339 .reduce_optimized,
340 .int_from_float_optimized,
341 .add_safe,
342 .sub_safe,
343 .mul_safe,
344 .intcast_safe,
345 => |tag| return cg.fail("TODO: implement spork8 inst: {s}", .{@tagName(tag)}),
346
347 .work_item_id,
348 .work_group_size,
349 .work_group_id,
350 => unreachable,
351 };
352}
353
354fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
355 _ = cg;
356 _ = inst;
357}
358
359fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
360 const zcu = cg.pt.zcu;
361 const func = zcu.funcInfo(cg.func_index);
362 return zcu.codegenFail(func.owner_nav, fmt, args);
363}
364
365fn extraLen(cg: *const CodeGen) u32 {
366 return @intCast(cg.mir_extra.items.len - cg.start_mir_extra_off);
367}
src/codegen/spork8/Mir.zig created+46
......@@ -0,0 +1,46 @@
1const Mir = @This();
2const InternPool = @import("../../InternPool.zig");
3
4const builtin = @import("builtin");
5const std = @import("std");
6const assert = std.debug.assert;
7
8instruction_tags: []const Inst.Tag,
9instruction_datas: []const Inst.Data,
10extra: []const u32,
11
12pub const Inst = struct {
13 tag: Tag,
14 data: Data,
15
16 /// The position of a given MIR isntruction with the instruction list.
17 pub const Index = enum(u32) {
18 _,
19 };
20
21 pub const Tag = enum(u8) {
22 /// imm8
23 set_page_i = 0x04,
24 /// imm8
25 set_addr_i = 0x09,
26 /// imm8
27 load_i = 0x10,
28 /// index
29 jump,
30 };
31
32 /// All instructions contain a 4-byte payload, which is contained within
33 /// this union. `Tag` determines which union tag is active, as well as
34 /// how to interpret the data within.
35 pub const Data = union {
36 imm8: u8,
37 index: Index,
38
39 comptime {
40 switch (builtin.mode) {
41 .Debug, .ReleaseSafe => {},
42 .ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4),
43 }
44 }
45 };
46};
src/dev.zig+16
......@@ -60,6 +60,10 @@ pub const Env = enum {
6060 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target loongarch(32/64)-linux --listen=-`
6161 @"loongarch-linux",
6262
63 /// - sema
64 /// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
65 spork8,
66
6367 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
6468 return switch (dev_env) {
6569 .full => true,
......@@ -102,6 +106,7 @@ pub const Env = enum {
102106 .sparc64_backend,
103107 .spirv_backend,
104108 .loongarch_backend,
109 .spork8_backend,
105110 .lld_linker,
106111 .coff_linker,
107112 .coff2_linker,
......@@ -112,6 +117,7 @@ pub const Env = enum {
112117 .wasm_linker,
113118 .spirv_linker,
114119 .plan9_linker,
120 .spork8_linker,
115121 .jit_command,
116122 => true,
117123 .cc_command,
......@@ -239,6 +245,14 @@ pub const Env = enum {
239245 => true,
240246 else => Env.sema.supports(feature),
241247 },
248 .spork8 => switch (feature) {
249 .stdio_listen,
250 .incremental,
251 .spork8_backend,
252 .spork8_linker,
253 => true,
254 else => Env.sema.supports(feature),
255 },
242256 };
243257 }
244258
......@@ -303,6 +317,7 @@ pub const Feature = enum {
303317 sparc64_backend,
304318 spirv_backend,
305319 loongarch_backend,
320 spork8_backend,
306321
307322 lld_linker,
308323 coff_linker,
......@@ -314,6 +329,7 @@ pub const Feature = enum {
314329 wasm_linker,
315330 spirv_linker,
316331 plan9_linker,
332 spork8_linker,
317333};
318334
319335/// Makes the code following the call to this function unreachable if `feature` is disabled.
src/link.zig+10
......@@ -673,6 +673,7 @@ pub const File = struct {
673673 });
674674 },
675675 .plan9 => unreachable,
676 .spork8 => dev.check(.spork8_linker),
676677 }
677678 }
678679
......@@ -750,6 +751,7 @@ pub const File = struct {
750751 },
751752 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
752753 .plan9 => unreachable,
754 .spork8 => dev.check(.spork8_linker),
753755 }
754756 }
755757
......@@ -1025,6 +1027,7 @@ pub const File = struct {
10251027 .spirv => unreachable,
10261028 .wasm => unreachable,
10271029 .plan9 => unreachable,
1030 .spork8 => unreachable,
10281031 inline else => |tag| {
10291032 dev.check(tag.devFeature());
10301033 return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info);
......@@ -1047,6 +1050,7 @@ pub const File = struct {
10471050 .spirv => unreachable,
10481051 .wasm => unreachable,
10491052 .plan9 => unreachable,
1053 .spork8 => unreachable,
10501054 inline else => |tag| {
10511055 dev.check(tag.devFeature());
10521056 return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align);
......@@ -1064,6 +1068,7 @@ pub const File = struct {
10641068 .spirv => unreachable,
10651069 .wasm => unreachable,
10661070 .plan9 => unreachable,
1071 .spork8 => unreachable,
10671072 inline else => |tag| {
10681073 dev.check(tag.devFeature());
10691074 return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info);
......@@ -1088,6 +1093,7 @@ pub const File = struct {
10881093 .spirv,
10891094 .plan9,
10901095 .lld,
1096 .spork8,
10911097 => return .unimplemented,
10921098 inline else => |tag| {
10931099 dev.check(tag.devFeature());
......@@ -1266,6 +1272,7 @@ pub const File = struct {
12661272 c,
12671273 wasm,
12681274 spirv,
1275 spork8,
12691276 plan9,
12701277 lld,
12711278
......@@ -1280,6 +1287,7 @@ pub const File = struct {
12801287 .spirv => SpirV,
12811288 .lld => Lld,
12821289 .plan9 => comptime unreachable,
1290 .spork8 => Spork8,
12831291 };
12841292 }
12851293
......@@ -1292,6 +1300,7 @@ pub const File = struct {
12921300 .plan9 => .plan9,
12931301 .c => .c,
12941302 .spirv => .spirv,
1303 .spork8 => .spork8,
12951304 .hex => @panic("TODO implement hex object format"),
12961305 .raw => @panic("TODO implement raw object format"),
12971306 };
......@@ -1373,6 +1382,7 @@ pub const File = struct {
13731382 pub const Lld = @import("link/Lld.zig");
13741383 pub const C = @import("link/C.zig");
13751384 pub const Coff2 = @import("link/Coff.zig");
1385 pub const Spork8 = @import("link/Spork8.zig");
13761386 pub const Elf = @import("link/Elf.zig");
13771387 pub const Elf2 = @import("link/Elf2.zig");
13781388 pub const MachO = @import("link/MachO.zig");
src/link/Spork8.zig created+188
......@@ -0,0 +1,188 @@
1const Spork8 = @This();
2const builtin = @import("builtin");
3const build_options = @import("build_options");
4
5const std = @import("std");
6const Io = std.Io;
7const Allocator = std.mem.Allocator;
8const assert = std.debug.assert;
9const Path = std.Build.Cache.Path;
10const log = std.log.scoped(.link);
11
12const Air = @import("../Air.zig");
13const InternPool = @import("../InternPool.zig");
14const Zcu = @import("../Zcu.zig");
15const CodeGen = @import("../codegen/spork8/CodeGen.zig");
16const codegen = @import("../codegen.zig");
17const Mir = @import("../codegen/spork8/Mir.zig");
18const link = @import("../link.zig");
19const Compilation = @import("../Compilation.zig");
20const Liveness = @import("../Air/Liveness.zig");
21const dev = @import("../dev.zig");
22const Value = @import("../Value.zig");
23
24base: link.File,
25funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, CodeGen.Function) = .empty,
26/// All MIR instructions for all Zcu functions.
27mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
28/// Corresponds to `mir_instructions`.
29mir_extra: std.ArrayListUnmanaged(u32) = .empty,
30
31pub fn open(
32 arena: Allocator,
33 comp: *Compilation,
34 emit: Path,
35 options: link.File.OpenOptions,
36) !*Spork8 {
37 // TODO: restore saved linker state, don't truncate the file, and
38 // participate in incremental compilation.
39 return createEmpty(arena, comp, emit, options);
40}
41
42pub fn createEmpty(
43 arena: Allocator,
44 comp: *Compilation,
45 emit: Path,
46 options: link.File.OpenOptions,
47) !*Spork8 {
48 const target = comp.root_mod.resolved_target.result;
49 assert(target.ofmt == .spork8);
50 assert(comp.config.output_mode == .Exe);
51 const io = comp.io;
52
53 const spork8 = try arena.create(Spork8);
54 spork8.* = .{
55 .base = .{
56 .tag = .spork8,
57 .comp = comp,
58 .emit = emit,
59 .gc_sections = options.gc_sections orelse true,
60 .print_gc_sections = options.print_gc_sections,
61 .stack_size = options.stack_size orelse switch (target.os.tag) {
62 .freestanding => 1 * 1024 * 1024, // 1 MiB
63 else => 16 * 1024 * 1024, // 16 MiB
64 },
65 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
66 .file = null,
67 .build_id = options.build_id,
68 },
69 };
70 errdefer spork8.base.destroy();
71
72 spork8.base.file = try emit.root_dir.handle.createFile(io, emit.sub_path, .{
73 .truncate = true,
74 .read = true,
75 });
76
77 return spork8;
78}
79
80pub fn deinit(spork8: *Spork8) void {
81 const gpa = spork8.base.comp.gpa;
82 _ = gpa;
83}
84
85pub fn updateFunc(
86 spork8: *Spork8,
87 pt: Zcu.PerThread,
88 func_index: InternPool.Index,
89 any_mir: *const codegen.AnyMir,
90) !void {
91 dev.check(.spork8_backend);
92 // This linker implementation only works with codegen backend `.stage2_wasm`.
93 const mir = &any_mir.spork8;
94 const zcu = pt.zcu;
95 const gpa = zcu.gpa;
96 const ip = &zcu.intern_pool;
97 const owner_nav = zcu.funcInfo(func_index).owner_nav;
98 _ = gpa;
99 _ = mir;
100 _ = spork8;
101 log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)});
102}
103
104// Generate code for the "Nav", storing it in memory to be later written to
105// the file on flush().
106pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
107 _ = spork8;
108 const zcu = pt.zcu;
109 const ip = &zcu.intern_pool;
110 const nav = ip.getNav(nav_index);
111 log.debug("updateNav {f}", .{nav.fqn.fmt(ip)});
112}
113
114pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
115 _ = spork8;
116 _ = pt;
117 _ = ti_id;
118}
119
120pub fn deleteExport(
121 spork8: *Spork8,
122 exported: Zcu.Exported,
123 name: InternPool.NullTerminatedString,
124) void {
125 const zcu = spork8.base.comp.zcu.?;
126 const ip = &zcu.intern_pool;
127 const name_slice = name.toSlice(ip);
128 switch (exported) {
129 .nav => |nav_index| {
130 log.debug("deleteExport '{s}' nav={d}", .{ name_slice, @backingInt(nav_index) });
131 },
132 .uav => |uav_index| {
133 log.debug("deleteExport '{s}' uav={d}", .{ name_slice, @backingInt(uav_index) });
134 },
135 }
136}
137
138pub fn updateExports(
139 spork8: *Spork8,
140 pt: Zcu.PerThread,
141 export_indices: []const Zcu.Export.Index,
142) !void {
143 _ = spork8;
144 const zcu = pt.zcu;
145 const ip = &zcu.intern_pool;
146
147 for (export_indices) |export_idx| {
148 const exp = export_idx.ptr(zcu);
149 const name_slice = exp.opts.name.toSlice(ip);
150 switch (exp.exported) {
151 .nav => |nav_index| {
152 log.debug("updateExports {q} nav={d}", .{ name_slice, @backingInt(nav_index) });
153 },
154 .uav => |uav_index| {
155 log.debug("updateExports {q} uav={d}", .{ name_slice, @backingInt(uav_index) });
156 },
157 }
158 }
159}
160
161pub fn loadInput(spork8: *Spork8, input: link.Input) !void {
162 _ = input;
163 const comp = spork8.base.comp;
164 const diags = &comp.link_diags;
165 return diags.failParse("spork8 does not support linking files together", .{});
166}
167
168pub fn flush(
169 spork8: *Spork8,
170 arena: Allocator,
171 tid: Zcu.PerThread.Id,
172 prog_node: std.Progress.Node,
173) link.Error!void {
174 const sub_prog_node = prog_node.start("Spork8 Flush", 0);
175 defer sub_prog_node.end();
176
177 _ = spork8;
178 _ = arena;
179 _ = tid;
180 log.debug("TODO implement flush", .{});
181}
182
183pub fn prelink(spork8: *Spork8, prog_node: std.Progress.Node) link.Error!void {
184 const sub_prog_node = prog_node.start("Spork8 Prelink", 0);
185 defer sub_prog_node.end();
186
187 _ = spork8;
188}
src/target.zig+5
......@@ -189,6 +189,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
189189 // LLVM does not support these object formats:
190190 .c,
191191 .plan9,
192 .spork8,
192193 => return false,
193194
194195 .coff,
......@@ -271,6 +272,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
271272 .sheb,
272273 .x86_16,
273274 .xtensaeb,
275 .spork8,
274276 => false,
275277 };
276278}
......@@ -433,6 +435,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
433435 }
434436 switch (target.cpu.arch) {
435437 .spirv32, .spirv64 => return .no,
438 .spork8 => return .no,
436439 // Remove this once https://github.com/ziglang/zig/issues/23714 is fixed
437440 .amdgcn => return .no,
438441 else => {},
......@@ -445,6 +448,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
445448
446449pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only, llvm_lld_only } {
447450 switch (target.cpu.arch) {
451 .spork8 => return .no,
448452 .spirv32, .spirv64 => return .no,
449453 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
450454 .nvptx, .nvptx64 => return .no,
......@@ -929,6 +933,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.lang.CompilerBa
929933 .wasm32, .wasm64 => .stage2_wasm,
930934 .x86 => .stage2_x86,
931935 .x86_64 => .stage2_x86_64,
936 .spork8 => .zsf_spork8,
932937 else => .other,
933938 };
934939}