authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-27 21:18:14+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-27 21:18:14+02:00
logc6204ba3c2e83772e076c7c79095f4093dad0f94
tree2f1070b3f8d7577f02e9732692ff19c966e0a595
parentc3723c05f0349efb6f2b28655f886d58853a9d3a
parent521cc292e6ff43cffc0f54d9b1a5243ba0a766e6

Merge pull request 'spork8 backend' (#36627) from spork8 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36627

14 files changed, 1254 insertions(+), 166 deletions(-)

lib/std/Build/Configuration.zig+1
...@@ -2341,6 +2341,7 @@ pub const TargetQuery = struct {...@@ -2341,6 +2341,7 @@ pub const TargetQuery = struct {
2341 sheb,2341 sheb,
2342 sparc,2342 sparc,
2343 sparc64,2343 sparc64,
2344 spork8,
2344 spirv32,2345 spirv32,
2345 spirv64,2346 spirv64,
2346 thumb,2347 thumb,
lib/std/Target.zig+170-143
...@@ -105,6 +105,7 @@ pub const Os = struct {...@@ -105,6 +105,7 @@ pub const Os = struct {
105 .plan9 => arch.plan9Ext(),105 .plan9 => arch.plan9Ext(),
106 else => switch (arch) {106 else => switch (arch) {
107 .wasm32, .wasm64 => ".wasm",107 .wasm32, .wasm64 => ".wasm",
108 .spork8 => ".bin",
108 else => "",109 else => "",
109 },110 },
110 };111 };
...@@ -791,6 +792,7 @@ pub const s390x = @import("Target/s390x.zig");...@@ -791,6 +792,7 @@ pub const s390x = @import("Target/s390x.zig");
791pub const sh = @import("Target/generic.zig");792pub const sh = @import("Target/generic.zig");
792pub const sparc = @import("Target/sparc.zig");793pub const sparc = @import("Target/sparc.zig");
793pub const spirv = @import("Target/spirv.zig");794pub const spirv = @import("Target/spirv.zig");
795pub const spork8 = @import("Target/generic.zig");
794pub const ve = @import("Target/ve.zig");796pub const ve = @import("Target/ve.zig");
795pub const wasm = @import("Target/wasm.zig");797pub const wasm = @import("Target/wasm.zig");
796pub const x86 = @import("Target/x86.zig");798pub const x86 = @import("Target/x86.zig");
...@@ -1079,6 +1081,7 @@ pub const ObjectFormat = enum {...@@ -1079,6 +1081,7 @@ pub const ObjectFormat = enum {
1079 else => switch (arch) {1081 else => switch (arch) {
1080 .spirv32, .spirv64 => .spirv,1082 .spirv32, .spirv64 => .spirv,
1081 .wasm32, .wasm64 => .wasm,1083 .wasm32, .wasm64 => .wasm,
1084 .spork8 => .raw,
1082 else => .elf,1085 else => .elf,
1083 },1086 },
1084 };1087 };
...@@ -1128,6 +1131,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {...@@ -1128,6 +1131,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
1128 .spirv64,1131 .spirv64,
1129 .wasm32,1132 .wasm32,
1130 .wasm64,1133 .wasm64,
1134 .spork8,
1131 => .NONE,1135 => .NONE,
1132 };1136 };
1133}1137}
...@@ -1195,6 +1199,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {...@@ -1195,6 +1199,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
1195 .xcore,1199 .xcore,
1196 .xtensa,1200 .xtensa,
1197 .xtensaeb,1201 .xtensaeb,
1202 .spork8,
1198 => .UNKNOWN,1203 => .UNKNOWN,
1199 };1204 };
1200}1205}
...@@ -1399,6 +1404,7 @@ pub const Cpu = struct {...@@ -1399,6 +1404,7 @@ pub const Cpu = struct {
1399 sheb,1404 sheb,
1400 sparc,1405 sparc,
1401 sparc64,1406 sparc64,
1407 spork8,
1402 spirv32,1408 spirv32,
1403 spirv64,1409 spirv64,
1404 thumb,1410 thumb,
...@@ -1451,6 +1457,7 @@ pub const Cpu = struct {...@@ -1451,6 +1457,7 @@ pub const Cpu = struct {
1451 xcore,1457 xcore,
1452 xtensa,1458 xtensa,
1453 z80,1459 z80,
1460 spork8,
1454 };1461 };
14551462
1456 pub inline fn family(arch: Arch) Family {1463 pub inline fn family(arch: Arch) Family {
...@@ -1489,6 +1496,7 @@ pub const Cpu = struct {...@@ -1489,6 +1496,7 @@ pub const Cpu = struct {
1489 .x86_16, .x86, .x86_64 => .x86,1496 .x86_16, .x86, .x86_64 => .x86,
1490 .xcore => .xcore,1497 .xcore => .xcore,
1491 .xtensa, .xtensaeb => .xtensa,1498 .xtensa, .xtensaeb => .xtensa,
1499 .spork8 => .spork8,
1492 };1500 };
1493 }1501 }
14941502
...@@ -1753,6 +1761,7 @@ pub const Cpu = struct {...@@ -1753,6 +1761,7 @@ pub const Cpu = struct {
1753 .sparc,1761 .sparc,
1754 .sparc64,1762 .sparc64,
1755 .xtensaeb,1763 .xtensaeb,
1764 .spork8,
1756 => .big,1765 => .big,
17571766
1758 // GPU endianness is opaque. For now, assume little endian.1767 // GPU endianness is opaque. For now, assume little endian.
...@@ -2011,6 +2020,9 @@ pub const Cpu = struct {...@@ -2011,6 +2020,9 @@ pub const Cpu = struct {
2011 .ez80_cet,2020 .ez80_cet,
2012 .ez80_tiflags,2021 .ez80_tiflags,
2013 => &.{.ez80},2022 => &.{.ez80},
2023
2024 .spork8,
2025 => &.{.spork8},
2014 };2026 };
2015 }2027 }
2016 };2028 };
...@@ -2980,6 +2992,7 @@ pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {...@@ -2980,6 +2992,7 @@ pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
2980 .avr,2992 .avr,
2981 .msp430,2993 .msp430,
2982 .x86_16,2994 .x86_16,
2995 .spork8,
2983 => 16,2996 => 16,
29842997
2985 .ez80,2998 .ez80,
...@@ -3104,6 +3117,8 @@ pub fn stackAlignment(target: *const Target) u16 {...@@ -3104,6 +3117,8 @@ pub fn stackAlignment(target: *const Target) u16 {
31043117
3105 .kvx => return 32,3118 .kvx => return 32,
31063119
3120 .spork8 => return 256,
3121
3107 else => {},3122 else => {},
3108 }3123 }
31093124
...@@ -3123,6 +3138,7 @@ pub fn stackGrowth(target: *const Target) StackGrowth {...@@ -3123,6 +3138,7 @@ pub fn stackGrowth(target: *const Target) StackGrowth {
3123 return switch (target.cpu.arch) {3138 return switch (target.cpu.arch) {
3124 .hppa,3139 .hppa,
3125 .hppa64,3140 .hppa64,
3141 .spork8,
3126 => .up,3142 => .up,
3127 else => .down,3143 else => .down,
3128 };3144 };
...@@ -3210,7 +3226,7 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 {...@@ -3210,7 +3226,7 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) ?u16 {
32103226
3211/// Returns `null` if no C ABI is defined for this target.3227/// Returns `null` if no C ABI is defined for this target.
3212pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {3228pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3213 switch (target.os.tag) {3229 return switch (target.os.tag) {
3214 .freestanding,3230 .freestanding,
3215 .other,3231 .other,
3216 .ashetos,3232 .ashetos,
...@@ -3218,49 +3234,56 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3218,49 +3234,56 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3218 .msp430,3234 .msp430,
3219 .x86_16,3235 .x86_16,
3220 => switch (c_type) {3236 => switch (c_type) {
3221 .char => return 8,3237 .char => 8,
3222 .short, .ushort, .int, .uint => return 16,3238 .short, .ushort, .int, .uint => 16,
3223 .float, .long, .ulong => return 32,3239 .float, .long, .ulong => 32,
3224 .longlong, .ulonglong, .double, .longdouble => return 64,3240 .longlong, .ulonglong, .double, .longdouble => 64,
3225 },3241 },
3226 .avr => switch (c_type) {3242 .avr => switch (c_type) {
3227 .char => return 8,3243 .char => 8,
3228 .short, .ushort, .int, .uint => return 16,3244 .short, .ushort, .int, .uint => 16,
3229 .long, .ulong, .float, .double, .longdouble => return 32,3245 .long, .ulong, .float, .double, .longdouble => 32,
3230 .longlong, .ulonglong => return 64,3246 .longlong, .ulonglong => 64,
3247 },
3248 // https://github.com/benanderman/spork-8/blob/main/Programming.md
3249 .spork8 => switch (c_type) {
3250 .char => 8,
3251 .short, .ushort, .int, .uint => 16,
3252 .long, .ulong, .float => 32,
3253 .double, .longdouble, .longlong, .ulonglong => 64,
3231 },3254 },
3232 .mips64,3255 .mips64,
3233 .mips64el,3256 .mips64el,
3234 => switch (c_type) {3257 => switch (c_type) {
3235 .char => return 8,3258 .char => 8,
3236 .short, .ushort => return 16,3259 .short, .ushort => 16,
3237 .int, .uint, .float => return 32,3260 .int, .uint, .float => 32,
3238 .long, .ulong => switch (target.abi) {3261 .long, .ulong => switch (target.abi) {
3239 .abin32 => return 32,3262 .abin32 => 32,
3240 else => return 64,3263 else => 64,
3241 },3264 },
3242 .longlong, .ulonglong, .double => return 64,3265 .longlong, .ulonglong, .double => 64,
3243 .longdouble => return 128,3266 .longdouble => 128,
3244 },3267 },
3245 .x86_64 => switch (c_type) {3268 .x86_64 => switch (c_type) {
3246 .char => return 8,3269 .char => 8,
3247 .short, .ushort => return 16,3270 .short, .ushort => 16,
3248 .int, .uint, .float => return 32,3271 .int, .uint, .float => 32,
3249 .long, .ulong => switch (target.abi) {3272 .long, .ulong => switch (target.abi) {
3250 .x32 => return 32,3273 .x32 => 32,
3251 else => return 64,3274 else => 64,
3252 },3275 },
3253 .longlong, .ulonglong, .double => return 64,3276 .longlong, .ulonglong, .double => 64,
3254 .longdouble => return 80,3277 .longdouble => 80,
3255 },3278 },
3256 else => switch (c_type) {3279 else => switch (c_type) {
3257 .char => return 8,3280 .char => 8,
3258 .short, .ushort => return 16,3281 .short, .ushort => 16,
3259 .int, .uint, .float => return 32,3282 .int, .uint, .float => 32,
3260 .long, .ulong => return target.ptrBitWidth(),3283 .long, .ulong => target.ptrBitWidth(),
3261 .longlong, .ulonglong, .double => return 64,3284 .longlong, .ulonglong, .double => 64,
3262 .longdouble => switch (target.cpu.arch) {3285 .longdouble => switch (target.cpu.arch) {
3263 .x86 => return 80,3286 .x86 => 80,
32643287
3265 .alpha,3288 .alpha,
3266 .riscv32,3289 .riscv32,
...@@ -3280,9 +3303,9 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3280,9 +3303,9 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3280 .loongarch32,3303 .loongarch32,
3281 .loongarch64,3304 .loongarch64,
3282 .ve,3305 .ve,
3283 => return 128,3306 => 128,
32843307
3285 else => return 64,3308 else => 64,
3286 },3309 },
3287 },3310 },
3288 },3311 },
...@@ -3309,60 +3332,60 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3309,60 +3332,60 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3309 .mips64,3332 .mips64,
3310 .mips64el,3333 .mips64el,
3311 => switch (c_type) {3334 => switch (c_type) {
3312 .char => return 8,3335 .char => 8,
3313 .short, .ushort => return 16,3336 .short, .ushort => 16,
3314 .int, .uint, .float => return 32,3337 .int, .uint, .float => 32,
3315 .long, .ulong => switch (target.abi) {3338 .long, .ulong => switch (target.abi) {
3316 .gnuabin32, .muslabin32, .abin32 => return 32,3339 .gnuabin32, .muslabin32, .abin32 => 32,
3317 else => return 64,3340 else => 64,
3318 },3341 },
3319 .longlong, .ulonglong, .double => return 64,3342 .longlong, .ulonglong, .double => 64,
3320 .longdouble => return 128,3343 .longdouble => 128,
3321 },3344 },
3322 .x86_64 => switch (c_type) {3345 .x86_64 => switch (c_type) {
3323 .char => return 8,3346 .char => 8,
3324 .short, .ushort => return 16,3347 .short, .ushort => 16,
3325 .int, .uint, .float => return 32,3348 .int, .uint, .float => 32,
3326 .long, .ulong => switch (target.abi) {3349 .long, .ulong => switch (target.abi) {
3327 .gnux32, .muslx32, .x32 => return 32,3350 .gnux32, .muslx32, .x32 => 32,
3328 else => return 64,3351 else => 64,
3329 },3352 },
3330 .longlong, .ulonglong, .double => return 64,3353 .longlong, .ulonglong, .double => 64,
3331 .longdouble => return 80,3354 .longdouble => 80,
3332 },3355 },
3333 else => switch (c_type) {3356 else => switch (c_type) {
3334 .char => return 8,3357 .char => 8,
3335 .short, .ushort => return 16,3358 .short, .ushort => 16,
3336 .int, .uint, .float => return 32,3359 .int, .uint, .float => 32,
3337 .long, .ulong => return target.ptrBitWidth(),3360 .long, .ulong => target.ptrBitWidth(),
3338 .longlong, .ulonglong, .double => return 64,3361 .longlong, .ulonglong, .double => 64,
3339 .longdouble => switch (target.cpu.arch) {3362 .longdouble => switch (target.cpu.arch) {
3340 .x86 => switch (target.abi) {3363 .x86 => switch (target.abi) {
3341 .android => return 64,3364 .android => 64,
3342 else => return 80,3365 else => 80,
3343 },3366 },
33443367
3345 .powerpc,3368 .powerpc,
3346 .powerpcle,3369 .powerpcle,
3347 => switch (target.abi) {3370 => switch (target.abi) {
3348 .musleabi, .musleabihf => return 64,3371 .musleabi, .musleabihf => 64,
3349 else => switch (target.os.tag) {3372 else => switch (target.os.tag) {
3350 .netbsd,3373 .netbsd,
3351 .openbsd,3374 .openbsd,
3352 => return 64,3375 => 64,
3353 else => return 128,3376 else => 128,
3354 },3377 },
3355 },3378 },
33563379
3357 .powerpc64,3380 .powerpc64,
3358 .powerpc64le,3381 .powerpc64le,
3359 => switch (target.abi) {3382 => switch (target.abi) {
3360 .musl => return 64,3383 .musl => 64,
3361 else => switch (target.os.tag) {3384 else => switch (target.os.tag) {
3362 .freebsd,3385 .freebsd,
3363 .openbsd,3386 .openbsd,
3364 => return 64,3387 => 64,
3365 else => return 128,3388 else => 128,
3366 },3389 },
3367 },3390 },
33683391
...@@ -3382,43 +3405,43 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3382,43 +3405,43 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3382 .loongarch32,3405 .loongarch32,
3383 .loongarch64,3406 .loongarch64,
3384 .ve,3407 .ve,
3385 => return 128,3408 => 128,
33863409
3387 else => return 64,3410 else => 64,
3388 },3411 },
3389 },3412 },
3390 },3413 },
33913414
3392 .windows, .uefi => switch (target.cpu.arch) {3415 .windows, .uefi => switch (target.cpu.arch) {
3393 .x86 => switch (c_type) {3416 .x86 => switch (c_type) {
3394 .char => return 8,3417 .char => 8,
3395 .short, .ushort => return 16,3418 .short, .ushort => 16,
3396 .int, .uint, .float => return 32,3419 .int, .uint, .float => 32,
3397 .long, .ulong => return 32,3420 .long, .ulong => 32,
3398 .longlong, .ulonglong, .double => return 64,3421 .longlong, .ulonglong, .double => 64,
3399 .longdouble => switch (target.abi) {3422 .longdouble => switch (target.abi) {
3400 .gnu => return 80,3423 .gnu => 80,
3401 else => return 64,3424 else => 64,
3402 },3425 },
3403 },3426 },
3404 .x86_64 => switch (c_type) {3427 .x86_64 => switch (c_type) {
3405 .char => return 8,3428 .char => 8,
3406 .short, .ushort => return 16,3429 .short, .ushort => 16,
3407 .int, .uint, .float => return 32,3430 .int, .uint, .float => 32,
3408 .long, .ulong => return 32,3431 .long, .ulong => 32,
3409 .longlong, .ulonglong, .double => return 64,3432 .longlong, .ulonglong, .double => 64,
3410 .longdouble => switch (target.abi) {3433 .longdouble => switch (target.abi) {
3411 .gnu => return 80,3434 .gnu => 80,
3412 else => return 64,3435 else => 64,
3413 },3436 },
3414 },3437 },
3415 else => switch (c_type) {3438 else => switch (c_type) {
3416 .char => return 8,3439 .char => 8,
3417 .short, .ushort => return 16,3440 .short, .ushort => 16,
3418 .int, .uint, .float => return 32,3441 .int, .uint, .float => 32,
3419 .long, .ulong => return 32,3442 .long, .ulong => 32,
3420 .longlong, .ulonglong, .double => return 64,3443 .longlong, .ulonglong, .double => 64,
3421 .longdouble => return 64,3444 .longdouble => 64,
3422 },3445 },
3423 },3446 },
34243447
...@@ -3430,75 +3453,75 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3430,75 +3453,75 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3430 .visionos,3453 .visionos,
3431 .watchos,3454 .watchos,
3432 => switch (c_type) {3455 => switch (c_type) {
3433 .char => return 8,3456 .char => 8,
3434 .short, .ushort => return 16,3457 .short, .ushort => 16,
3435 .int, .uint, .float => return 32,3458 .int, .uint, .float => 32,
3436 .long, .ulong => switch (target.cpu.arch) {3459 .long, .ulong => switch (target.cpu.arch) {
3437 .x86_64 => return 64,3460 .x86_64 => 64,
3438 else => switch (target.abi) {3461 else => switch (target.abi) {
3439 .ilp32 => return 32,3462 .ilp32 => 32,
3440 else => return 64,3463 else => 64,
3441 },3464 },
3442 },3465 },
3443 .longlong, .ulonglong, .double => return 64,3466 .longlong, .ulonglong, .double => 64,
3444 .longdouble => switch (target.cpu.arch) {3467 .longdouble => switch (target.cpu.arch) {
3445 .x86_64 => return 80,3468 .x86_64 => 80,
3446 else => return 64,3469 else => 64,
3447 },3470 },
3448 },3471 },
34493472
3450 .nvcl, .cuda => switch (c_type) {3473 .nvcl, .cuda => switch (c_type) {
3451 .char => return 8,3474 .char => 8,
3452 .short, .ushort => return 16,3475 .short, .ushort => 16,
3453 .int, .uint, .float => return 32,3476 .int, .uint, .float => 32,
3454 .long, .ulong => switch (target.cpu.arch) {3477 .long, .ulong => switch (target.cpu.arch) {
3455 .nvptx => return 32,3478 .nvptx => 32,
3456 .nvptx64 => return 64,3479 .nvptx64 => 64,
3457 else => return 64,3480 else => 64,
3458 },3481 },
3459 .longlong, .ulonglong, .double => return 64,3482 .longlong, .ulonglong, .double => 64,
3460 .longdouble => return 64,3483 .longdouble => 64,
3461 },3484 },
34623485
3463 .amdhsa, .amdpal, .mesa3d => switch (c_type) {3486 .amdhsa, .amdpal, .mesa3d => switch (c_type) {
3464 .char => return 8,3487 .char => 8,
3465 .short, .ushort => return 16,3488 .short, .ushort => 16,
3466 .int, .uint, .float => return 32,3489 .int, .uint, .float => 32,
3467 .long, .ulong, .longlong, .ulonglong, .double => return 64,3490 .long, .ulong, .longlong, .ulonglong, .double => 64,
3468 .longdouble => return 128,3491 .longdouble => 128,
3469 },3492 },
34703493
3471 .opencl, .vulkan => switch (c_type) {3494 .opencl, .vulkan => switch (c_type) {
3472 .char => return 8,3495 .char => 8,
3473 .short, .ushort => return 16,3496 .short, .ushort => 16,
3474 .int, .uint, .float => return 32,3497 .int, .uint, .float => 32,
3475 .long, .ulong, .double => return 64,3498 .long, .ulong, .double => 64,
3476 .longlong, .ulonglong => return 128,3499 .longlong, .ulonglong => 128,
3477 // Note: The OpenCL specification does not guarantee a particular size for long double,3500 // Note: The OpenCL specification does not guarantee a particular size for long double,
3478 // but clang uses 128 bits.3501 // but clang uses 128 bits.
3479 .longdouble => return 128,3502 .longdouble => 128,
3480 },3503 },
34813504
3482 .@"3ds" => switch (c_type) {3505 .@"3ds" => switch (c_type) {
3483 .char => return 8,3506 .char => 8,
3484 .short, .ushort => return 16,3507 .short, .ushort => 16,
3485 .int, .uint, .float, .long, .ulong => return 32,3508 .int, .uint, .float, .long, .ulong => 32,
3486 .longlong, .ulonglong, .double, .longdouble => return 64,3509 .longlong, .ulonglong, .double, .longdouble => 64,
3487 },3510 },
34883511
3489 .wiiu => switch (c_type) {3512 .wiiu => switch (c_type) {
3490 .char => return 8,3513 .char => 8,
3491 .short, .ushort => return 16,3514 .short, .ushort => 16,
3492 .int, .uint, .float, .long, .ulong => return 32,3515 .int, .uint, .float, .long, .ulong => 32,
3493 .longlong, .ulonglong, .double, .longdouble => return 64,3516 .longlong, .ulonglong, .double, .longdouble => 64,
3494 },3517 },
34953518
3496 .@"switch" => switch (c_type) {3519 .@"switch" => switch (c_type) {
3497 .char => return 8,3520 .char => 8,
3498 .short, .ushort => return 16,3521 .short, .ushort => 16,
3499 .int, .uint, .float => return 32,3522 .int, .uint, .float => 32,
3500 .long, .ulong, .longlong, .ulonglong, .double => return 64,3523 .long, .ulong, .longlong, .ulonglong, .double => 64,
3501 .longdouble => return 128,3524 .longdouble => 128,
3502 },3525 },
35033526
3504 .gba => switch (c_type) {3527 .gba => switch (c_type) {
...@@ -3509,41 +3532,41 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {...@@ -3509,41 +3532,41 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) ?u16 {
3509 },3532 },
35103533
3511 .psx => switch (c_type) {3534 .psx => switch (c_type) {
3512 .char => return 8,3535 .char => 8,
3513 .short, .ushort => return 16,3536 .short, .ushort => 16,
3514 .int, .uint, .long, .ulong, .float => return 32,3537 .int, .uint, .long, .ulong, .float => 32,
3515 .longlong, .ulonglong, .double, .longdouble => return 64,3538 .longlong, .ulonglong, .double, .longdouble => 64,
3516 },3539 },
3517 .ps4, .ps5 => switch (c_type) {3540 .ps4, .ps5 => switch (c_type) {
3518 .char => return 8,3541 .char => 8,
3519 .short, .ushort => return 16,3542 .short, .ushort => 16,
3520 .int, .uint, .float => return 32,3543 .int, .uint, .float => 32,
3521 .long, .ulong => return 64,3544 .long, .ulong => 64,
3522 .longlong, .ulonglong, .double => return 64,3545 .longlong, .ulonglong, .double => 64,
3523 .longdouble => return 80,3546 .longdouble => 80,
3524 },3547 },
3525 .psp, .vita => switch (c_type) {3548 .psp, .vita => switch (c_type) {
3526 .char => return 8,3549 .char => 8,
3527 .short, .ushort => return 16,3550 .short, .ushort => 16,
3528 .int, .uint, .float => return 32,3551 .int, .uint, .float => 32,
3529 .long, .ulong => return 64,3552 .long, .ulong => 64,
3530 .longlong, .ulonglong, .double, .longdouble => return 64,3553 .longlong, .ulonglong, .double, .longdouble => 64,
3531 },3554 },
3532 .tios => switch (c_type) {3555 .tios => switch (c_type) {
3533 .char => return 8,3556 .char => 8,
3534 .short, .ushort => return 16,3557 .short, .ushort => 16,
3535 .int, .uint => return 24,3558 .int, .uint => 24,
3536 .long, .ulong, .float, .double => return 32,3559 .long, .ulong, .float, .double => 32,
3537 .longlong, .ulonglong, .longdouble => return 64,3560 .longlong, .ulonglong, .longdouble => 64,
3538 },3561 },
35393562
3540 .opengl => return null,3563 .opengl => null,
35413564
3542 .ps3,3565 .ps3,
3543 .contiki,3566 .contiki,
3544 .managarm,3567 .managarm,
3545 => @panic("specify the C integer and float type sizes for this OS"),3568 => @panic("specify the C integer and float type sizes for this OS"),
3546 }3569 };
3547}3570}
35483571
3549/// Returns `null` if no C ABI is defined for this target.3572/// Returns `null` if no C ABI is defined for this target.
...@@ -3552,6 +3575,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {...@@ -3552,6 +3575,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
3552 switch (target.cpu.arch) {3575 switch (target.cpu.arch) {
3553 .avr,3576 .avr,
3554 .ez80,3577 .ez80,
3578 .spork8,
3555 => return 1,3579 => return 1,
3556 .x86 => switch (target.os.tag) {3580 .x86 => switch (target.os.tag) {
3557 .windows, .uefi => switch (c_type) {3581 .windows, .uefi => switch (c_type) {
...@@ -3650,6 +3674,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {...@@ -3650,6 +3674,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) ?u16 {
36503674
3651 .avr,3675 .avr,
3652 .ez80,3676 .ez80,
3677 .spork8,
3653 => unreachable, // Handled above.3678 => unreachable, // Handled above.
3654 }),3679 }),
3655 );3680 );
...@@ -3659,6 +3684,7 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {...@@ -3659,6 +3684,7 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
3659 return switch (target.cpu.arch) {3684 return switch (target.cpu.arch) {
3660 .avr,3685 .avr,
3661 .ez80,3686 .ez80,
3687 .spork8,
3662 => 1,3688 => 1,
36633689
3664 .msp430,3690 .msp430,
...@@ -3804,6 +3830,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention...@@ -3804,6 +3830,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
3804 .nvptx, .nvptx64 => .nvptx_device,3830 .nvptx, .nvptx64 => .nvptx_device,
3805 .spirv32, .spirv64 => .spirv_device,3831 .spirv32, .spirv64 => .spirv_device,
3806 .ez80 => .ez80_cet,3832 .ez80 => .ez80_cet,
3833 .spork8 => .spork8,
3807 };3834 };
3808}3835}
38093836
lib/std/debug.zig+2-2
...@@ -75,8 +75,8 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {...@@ -75,8 +75,8 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {
75 else => @import("debug/SelfInfo/Elf.zig"),75 else => @import("debug/SelfInfo/Elf.zig"),
76 },76 },
77 .macho => @import("debug/SelfInfo/MachO.zig"),77 .macho => @import("debug/SelfInfo/MachO.zig"),
78 .plan9, .spirv, .wasm => void,78 .plan9, .spirv, .wasm, .raw, .hex => void,
79 .c, .hex, .raw => unreachable,79 .c => unreachable,
80 };80 };
81}81}
8282
lib/std/lang.zig+7
...@@ -391,6 +391,10 @@ pub const CallingConvention = union(enum(u8)) {...@@ -391,6 +391,10 @@ pub const CallingConvention = union(enum(u8)) {
391 ez80_cet,391 ez80_cet,
392 ez80_tiflags,392 ez80_tiflags,
393393
394 // Calling convention used by
395 // [snake2p example program](https://github.com/benanderman/spork-8/blob/1bce10a2c3a3888a3f4ca8208112afbc5973fda4/Code/programs/snake2p.asm)
396 spork8,
397
394 /// Options shared across most calling conventions.398 /// Options shared across most calling conventions.
395 pub const CommonOptions = struct {399 pub const CommonOptions = struct {
396 /// The boundary the stack is aligned to when the function is called.400 /// The boundary the stack is aligned to when the function is called.
...@@ -1319,6 +1323,9 @@ pub const CompilerBackend = enum(u64) {...@@ -1319,6 +1323,9 @@ pub const CompilerBackend = enum(u64) {
1319 /// The reference implementation self-hosted compiler of Zig, using the1323 /// The reference implementation self-hosted compiler of Zig, using the
1320 /// loongarch backend.1324 /// loongarch backend.
1321 stage2_loongarch = 13,1325 stage2_loongarch = 13,
1326 /// The Zig Software Foundation self-hosted implementation of Zig. Backend
1327 /// originally contributed by Ben Anderman in 2026.
1328 zsf_spork8 = 14,
13221329
1323 _,1330 _,
1324};1331};
lib/std/zig/llvm/Builder.zig+2
...@@ -162,6 +162,7 @@ pub fn tripleForTarget(allocator: Allocator, target: *const std.Target) ![]const...@@ -162,6 +162,7 @@ pub fn tripleForTarget(allocator: Allocator, target: *const std.Target) ![]const
162 .propeller,162 .propeller,
163 .sh,163 .sh,
164 .sheb,164 .sheb,
165 .spork8,
165 .x86_16,166 .x86_16,
166 .xtensaeb,167 .xtensaeb,
167 => unreachable, // Gated by hasLlvmSupport().168 => unreachable, // Gated by hasLlvmSupport().
...@@ -577,6 +578,7 @@ pub const DataLayout = struct {...@@ -577,6 +578,7 @@ pub const DataLayout = struct {
577 .sheb,578 .sheb,
578 .x86_16,579 .x86_16,
579 .xtensaeb,580 .xtensaeb,
581 .spork8,
580 => unreachable,582 => unreachable,
581 };583 };
582 }584 }
src/Zcu.zig+5
...@@ -4042,6 +4042,7 @@ pub fn atomicPtrAlignment(...@@ -4042,6 +4042,7 @@ pub fn atomicPtrAlignment(
4042 const target = zcu.getTarget();4042 const target = zcu.getTarget();
4043 const max_atomic_bits: u16 = switch (target.cpu.arch) {4043 const max_atomic_bits: u16 = switch (target.cpu.arch) {
4044 .ez80,4044 .ez80,
4045 .spork8,
4045 => 8,4046 => 8,
40464047
4047 .aarch64,4048 .aarch64,
...@@ -4697,6 +4698,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4697,6 +4698,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4697 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,4698 .loongarch64_lp64, .loongarch32_ilp32, .naked => true,
4698 else => false,4699 else => false,
4699 },4700 },
4701 .zsf_spork8 => switch (cc) {
4702 .spork8, .naked => true,
4703 else => false,
4704 },
4700 };4705 };
4701 if (!backend_ok) return .{ .bad_backend = backend };4706 if (!backend_ok) return .{ .bad_backend = backend };
4702 return .ok;4707 return .ok;
src/codegen.zig+7
...@@ -38,6 +38,7 @@ fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {...@@ -38,6 +38,7 @@ fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {
38 .stage2_powerpc => unreachable,38 .stage2_powerpc => unreachable,
39 .stage2_riscv64 => .riscv64_backend,39 .stage2_riscv64 => .riscv64_backend,
40 .stage2_sparc64 => .sparc64_backend,40 .stage2_sparc64 => .sparc64_backend,
41 .zsf_spork8 => .spork8_backend,
41 .stage2_spirv => .spirv_backend,42 .stage2_spirv => .spirv_backend,
42 .stage2_wasm => .wasm_backend,43 .stage2_wasm => .wasm_backend,
43 .stage2_x86 => .x86_backend,44 .stage2_x86 => .x86_backend,
...@@ -58,6 +59,7 @@ fn importBackend(comptime backend: std.lang.CompilerBackend) type {...@@ -58,6 +59,7 @@ fn importBackend(comptime backend: std.lang.CompilerBackend) type {
58 .stage2_riscv64 => @import("codegen/riscv64/CodeGen.zig"),59 .stage2_riscv64 => @import("codegen/riscv64/CodeGen.zig"),
59 .stage2_sparc64 => @import("codegen/sparc64/CodeGen.zig"),60 .stage2_sparc64 => @import("codegen/sparc64/CodeGen.zig"),
60 .stage2_spirv => @import("codegen/spirv/CodeGen.zig"),61 .stage2_spirv => @import("codegen/spirv/CodeGen.zig"),
62 .zsf_spork8 => @import("codegen/spork8/CodeGen.zig"),
61 .stage2_wasm => @import("codegen/wasm/CodeGen.zig"),63 .stage2_wasm => @import("codegen/wasm/CodeGen.zig"),
62 .stage2_x86, .stage2_x86_64 => @import("codegen/x86_64/CodeGen.zig"),64 .stage2_x86, .stage2_x86_64 => @import("codegen/x86_64/CodeGen.zig"),
63 _ => unreachable,65 _ => unreachable,
...@@ -78,6 +80,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co...@@ -78,6 +80,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
78 .stage2_x86,80 .stage2_x86,
79 .stage2_riscv64,81 .stage2_riscv64,
80 .stage2_sparc64,82 .stage2_sparc64,
83 .zsf_spork8,
81 .stage2_spirv,84 .stage2_spirv,
82 => |backend| {85 => |backend| {
83 dev.check(devFeatureForBackend(backend));86 dev.check(devFeatureForBackend(backend));
...@@ -107,6 +110,7 @@ pub const AnyMir = union {...@@ -107,6 +110,7 @@ pub const AnyMir = union {
107 wasm: if (dev.env.supports(.wasm_backend)) @import("codegen/wasm/Mir.zig") else noreturn,110 wasm: if (dev.env.supports(.wasm_backend)) @import("codegen/wasm/Mir.zig") else noreturn,
108 c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn,111 c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn,
109 spirv: if (dev.env.supports(.spirv_backend)) @import("codegen/spirv/Mir.zig") else noreturn,112 spirv: if (dev.env.supports(.spirv_backend)) @import("codegen/spirv/Mir.zig") else noreturn,
113 spork8: if (dev.env.supports(.spork8_backend)) @import("codegen/spork8/Mir.zig") else noreturn,
110114
111 pub inline fn tag(comptime backend: std.lang.CompilerBackend) []const u8 {115 pub inline fn tag(comptime backend: std.lang.CompilerBackend) []const u8 {
112 return switch (backend) {116 return switch (backend) {
...@@ -118,6 +122,7 @@ pub const AnyMir = union {...@@ -118,6 +122,7 @@ pub const AnyMir = union {
118 .stage2_wasm => "wasm",122 .stage2_wasm => "wasm",
119 .stage2_c => "c",123 .stage2_c => "c",
120 .stage2_spirv => "spirv",124 .stage2_spirv => "spirv",
125 .zsf_spork8 => "spork8",
121 else => unreachable,126 else => unreachable,
122 };127 };
123 }128 }
...@@ -135,6 +140,7 @@ pub const AnyMir = union {...@@ -135,6 +140,7 @@ pub const AnyMir = union {
135 .stage2_wasm,140 .stage2_wasm,
136 .stage2_c,141 .stage2_c,
137 .stage2_spirv,142 .stage2_spirv,
143 .zsf_spork8,
138 => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa),144 => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa),
139 }145 }
140 }146 }
...@@ -164,6 +170,7 @@ pub fn generateFunction(...@@ -164,6 +170,7 @@ pub fn generateFunction(
164 .stage2_x86_64,170 .stage2_x86_64,
165 .stage2_wasm,171 .stage2_wasm,
166 .stage2_c,172 .stage2_c,
173 .zsf_spork8,
167 .stage2_spirv,174 .stage2_spirv,
168 => |backend| {175 => |backend| {
169 dev.check(devFeatureForBackend(backend));176 dev.check(devFeatureForBackend(backend));
src/codegen/llvm.zig+2
...@@ -4393,6 +4393,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const...@@ -4393,6 +4393,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
4393 .spirv_vertex,4393 .spirv_vertex,
4394 .spirv_task,4394 .spirv_task,
4395 .spirv_mesh,4395 .spirv_mesh,
4396 .spork8,
4396 => null,4397 => null,
4397 };4398 };
4398}4399}
...@@ -4720,6 +4721,7 @@ pub fn initializeLLVMTarget(io: Io, arch: std.Target.Cpu.Arch) void {...@@ -4720,6 +4721,7 @@ pub fn initializeLLVMTarget(io: Io, arch: std.Target.Cpu.Arch) void {
4720 .propeller,4721 .propeller,
4721 .sh,4722 .sh,
4722 .sheb,4723 .sheb,
4724 .spork8,
4723 .x86_16,4725 .x86_16,
4724 .xtensaeb,4726 .xtensaeb,
4725 => unreachable,4727 => unreachable,
src/codegen/spork8/CodeGen.zig created+676
...@@ -0,0 +1,676 @@
1const std = @import("std");
2const mem = std.mem;
3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;
5
6const CodeGen = @This();
7const link = @import("../../link.zig");
8const Spork8 = link.File.Spork8;
9const Zcu = @import("../../Zcu.zig");
10const InternPool = @import("../../InternPool.zig");
11const Air = @import("../../Air.zig");
12const Liveness = Air.Liveness;
13const Mir = @import("Mir.zig");
14
15air: Air,
16liveness: Liveness,
17gpa: Allocator,
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),
24
25pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features {
26 return comptime &.initMany(&.{
27 .expand_bit_cast_safe,
28 .expand_int_cast_safe,
29 .expand_int_from_float_safe,
30 .expand_int_from_float_optimized_safe,
31 .expand_add_safe,
32 .expand_sub_safe,
33 .expand_mul_safe,
34
35 .expand_packed_load,
36 .expand_packed_store,
37 .expand_packed_agg_field_val,
38 .expand_packed_aggregate_init,
39 .expand_array_to_vector,
40
41 .scalarize_add,
42 .scalarize_add_optimized,
43 .scalarize_add_wrap,
44 .scalarize_add_sat,
45 .scalarize_sub,
46 .scalarize_sub_optimized,
47 .scalarize_sub_wrap,
48 .scalarize_sub_sat,
49 .scalarize_mul,
50 .scalarize_mul_optimized,
51 .scalarize_mul_wrap,
52 .scalarize_mul_sat,
53 .scalarize_div_float,
54 .scalarize_div_float_optimized,
55 .scalarize_div_trunc,
56 .scalarize_div_trunc_optimized,
57 .scalarize_div_floor,
58 .scalarize_div_floor_optimized,
59 .scalarize_div_ceil,
60 .scalarize_div_ceil_optimized,
61 .scalarize_div_exact,
62 .scalarize_div_exact_optimized,
63 .scalarize_rem,
64 .scalarize_rem_optimized,
65 .scalarize_mod,
66 .scalarize_mod_optimized,
67 .scalarize_max,
68 .scalarize_min,
69 .scalarize_add_with_overflow,
70 .scalarize_sub_with_overflow,
71 .scalarize_mul_with_overflow,
72 .scalarize_shl_with_overflow,
73 .scalarize_bit_and,
74 .scalarize_bit_or,
75 .scalarize_shr,
76 .scalarize_shr_exact,
77 .scalarize_shl,
78 .scalarize_shl_exact,
79 .scalarize_shl_sat,
80 .scalarize_xor,
81 .scalarize_not,
82 .scalarize_clz,
83 .scalarize_ctz,
84 .scalarize_popcount,
85 .scalarize_byte_swap,
86 .scalarize_bit_reverse,
87 .scalarize_sqrt,
88 .scalarize_sin,
89 .scalarize_cos,
90 .scalarize_tan,
91 .scalarize_exp,
92 .scalarize_exp2,
93 .scalarize_log,
94 .scalarize_log2,
95 .scalarize_log10,
96 .scalarize_abs,
97 .scalarize_floor,
98 .scalarize_ceil,
99 .scalarize_round,
100 .scalarize_trunc_float,
101 .scalarize_neg,
102 .scalarize_neg_optimized,
103 .scalarize_cmp_vector,
104 .scalarize_cmp_vector_optimized,
105 .scalarize_fptrunc,
106 .scalarize_fpext,
107 .scalarize_int_cast,
108 .scalarize_ptr_cast,
109 .scalarize_ptr_from_int,
110 .scalarize_int_from_ptr,
111 .scalarize_trunc,
112 .scalarize_int_from_float,
113 .scalarize_int_from_float_optimized,
114 .scalarize_float_from_int,
115 .scalarize_reduce,
116 .scalarize_reduce_optimized,
117 .scalarize_shuffle_one,
118 .scalarize_shuffle_two,
119 .scalarize_select,
120 .scalarize_mul_add,
121
122 .scalarize_bit_cast_padded_elems,
123 });
124}
125
126pub fn generate(
127 bin_file: *link.File,
128 pt: Zcu.PerThread,
129 func_index: InternPool.Index,
130 air: *const Air,
131 liveness: *const ?Air.Liveness,
132) link.Error!Mir {
133 _ = bin_file;
134 const zcu = pt.zcu;
135 const gpa = zcu.gpa;
136 const cg = zcu.funcInfo(func_index);
137
138 var code_gen: CodeGen = .{
139 .gpa = gpa,
140 .pt = pt,
141 .air = air.*,
142 .liveness = liveness.*.?,
143 .owner_nav = cg.owner_nav,
144 .func_index = func_index,
145 .mir_instructions = .empty,
146 .mir_extra = .empty,
147 };
148 defer code_gen.deinit();
149
150 return generateInner(&code_gen) catch |err| switch (err) {
151 error.AlreadyReported,
152 error.OutOfMemory,
153 => |e| return e,
154 };
155}
156
157pub fn deinit(cg: *CodeGen) void {
158 cg.* = undefined;
159}
160
161const InnerError = error{
162 AlreadyReported,
163 OutOfMemory,
164};
165
166fn generateInner(cg: *CodeGen) InnerError!Mir {
167 // Generate MIR for function body
168 try cg.genBody(cg.air.getMainBody());
169
170 try cg.mir_extra.shrinkToLen(cg.gpa);
171
172 return .{
173 .instructions = cg.mir_instructions.toOwnedSlice(),
174 .extra = cg.mir_extra.toOwnedSliceAssert(),
175 };
176}
177
178fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
179 const zcu = cg.pt.zcu;
180 const ip = &zcu.intern_pool;
181
182 for (body) |inst| {
183 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
184 try cg.genInst(inst);
185 }
186}
187
188fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
189 const air_tags = cg.air.instructions.items(.tag);
190 return switch (air_tags[@backingInt(inst)]) {
191 .inferred_alloc, .inferred_alloc_comptime => unreachable,
192
193 .add,
194 .add_sat,
195 .add_wrap,
196 .sub,
197 .sub_sat,
198 .sub_wrap,
199 .mul,
200 .mul_sat,
201 .mul_wrap,
202 .div_float,
203 .div_exact,
204 .div_trunc,
205 .div_floor,
206 .bit_and,
207 .bit_or,
208 .rem,
209 .mod,
210 .shl,
211 .shl_exact,
212 .shl_sat,
213 .shr,
214 .shr_exact,
215 .xor,
216 .max,
217 .min,
218 .mul_add,
219
220 .sqrt,
221 .sin,
222 .cos,
223 .tan,
224 .exp,
225 .exp2,
226 .log,
227 .log2,
228 .log10,
229 .floor,
230 .ceil,
231 .round,
232 .trunc_float,
233 .neg,
234
235 .abs,
236
237 .add_with_overflow,
238 .sub_with_overflow,
239 .shl_with_overflow,
240 .mul_with_overflow,
241
242 .clz,
243 .ctz,
244
245 .cmp_eq,
246 .cmp_gte,
247 .cmp_gt,
248 .cmp_lte,
249 .cmp_lt,
250 .cmp_neq,
251
252 .cmp_vector,
253
254 .array_elem_val,
255 .array_to_slice,
256 .alloc,
257 .arg,
258 .block,
259 .breakpoint,
260 .br,
261 .repeat,
262 .switch_dispatch,
263 .cond_br,
264 .fptrunc,
265 .fpext,
266 .int_from_float,
267 .float_from_int,
268 .get_union_tag,
269
270 .@"try",
271 .try_cold,
272 .try_ptr,
273 .try_ptr_cold,
274
275 .dbg_stmt,
276 .dbg_empty_stmt,
277 .dbg_inline_block,
278 .dbg_var_ptr,
279 .dbg_var_val,
280 .dbg_arg_inline,
281
282 .call,
283 .call_always_tail,
284 .call_never_tail,
285 .call_never_inline,
286
287 .is_err,
288 .is_non_err,
289
290 .is_null,
291 .is_non_null,
292 .is_null_ptr,
293 .is_non_null_ptr,
294
295 .load,
296 .loop,
297 .memset,
298 .memset_safe,
299 .not,
300 .optional_payload,
301 .optional_payload_ptr,
302 .optional_payload_ptr_set,
303 .ptr_add,
304 .ptr_sub,
305 .ptr_elem_ptr,
306 .ptr_elem_val,
307 .ret,
308 .ret_safe,
309 .ret_ptr,
310 .ret_load,
311 .splat,
312 .select,
313 .reduce,
314 .aggregate_init,
315 .union_init,
316 .prefetch,
317 .popcount,
318 .byte_swap,
319 .bit_reverse,
320
321 .slice,
322 .slice_len,
323 .slice_elem_val,
324 .slice_elem_ptr,
325 .slice_ptr,
326 .ptr_slice_len_ptr,
327 .ptr_slice_ptr_ptr,
328 .store,
329 .store_safe,
330
331 .set_union_tag,
332 .struct_field_ptr,
333 .struct_field_ptr_index_0,
334 .struct_field_ptr_index_1,
335 .struct_field_ptr_index_2,
336 .struct_field_ptr_index_3,
337 .field_parent_ptr,
338
339 .switch_br,
340 .loop_switch_br,
341 .trunc,
342
343 .wrap_optional,
344 .unwrap_errunion_payload,
345 .unwrap_errunion_payload_ptr,
346 .unwrap_errunion_err,
347 .unwrap_errunion_err_ptr,
348 .wrap_errunion_payload,
349 .wrap_errunion_err,
350 .errunion_payload_ptr_set,
351 .error_name,
352
353 .wasm_memory_size,
354 .wasm_memory_grow,
355
356 .memcpy,
357
358 .ret_addr,
359 .tag_name,
360
361 .error_set_has_value,
362 .frame_addr,
363
364 .is_err_ptr,
365 .is_non_err_ptr,
366
367 .err_return_trace,
368 .set_err_return_trace,
369 .save_err_return_trace_index,
370 .is_named_enum_value,
371 .addrspace_cast,
372 .c_va_arg,
373 .c_va_copy,
374 .c_va_end,
375 .c_va_start,
376 .memmove,
377
378 .atomic_load,
379 .atomic_store_unordered,
380 .atomic_store_monotonic,
381 .atomic_store_release,
382 .atomic_store_seq_cst,
383 .atomic_rmw,
384 .cmpxchg_weak,
385 .cmpxchg_strong,
386
387 .add_optimized,
388 .sub_optimized,
389 .mul_optimized,
390 .div_float_optimized,
391 .div_trunc_optimized,
392 .div_floor_optimized,
393 .div_exact_optimized,
394 .rem_optimized,
395 .mod_optimized,
396 .neg_optimized,
397 .cmp_lt_optimized,
398 .cmp_lte_optimized,
399 .cmp_eq_optimized,
400 .cmp_gte_optimized,
401 .cmp_gt_optimized,
402 .cmp_neq_optimized,
403 .cmp_vector_optimized,
404 .reduce_optimized,
405 .int_from_float_optimized,
406 .add_safe,
407 .sub_safe,
408 .mul_safe,
409 .div_ceil,
410 .div_ceil_optimized,
411 .bit_cast,
412 .bit_cast_safe,
413 .ptr_cast,
414 .ptr_from_int,
415 .int_from_ptr,
416 .error_cast,
417 .error_from_int,
418 .int_from_error,
419 .union_from_enum,
420 .int_cast,
421 .int_cast_safe,
422 .agg_field_val,
423 .array_to_vector,
424 .int_from_float_safe,
425 .int_from_float_optimized_safe,
426 .shuffle_one,
427 .shuffle_two,
428 .cmp_lte_errors_len,
429 .runtime_nav_ptr,
430 .spirv_runtime_array_len,
431 .legalize_vec_store_elem,
432 .legalize_vec_elem_val,
433 .legalize_compiler_rt_call,
434 => |tag| return cg.fail("TODO: implement spork8 inst: {t}", .{tag}),
435
436 .unreach => cg.airUnreachable(inst),
437 .assembly => cg.airAssembly(inst),
438 .trap => cg.airTrap(inst),
439
440 .work_item_id,
441 .work_group_size,
442 .work_group_id,
443 => unreachable,
444 };
445}
446
447fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
448 _ = cg;
449 _ = inst;
450}
451
452fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
453 _ = inst;
454 try cg.addTag(.halt);
455}
456
457fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
458 const unwrapped_asm = cg.air.unwrapAsm(inst);
459 const outputs = unwrapped_asm.outputs;
460 // const inputs = unwrapped_asm.inputs;
461
462 const zcu = cg.pt.zcu;
463 // const output_ty = cg.typeOfIndex(inst);
464
465 if (outputs.len != 0) {
466 @panic("TODO: Support assembly outputs");
467 }
468
469 var constValues: std.array_hash_map.String(u8) = .empty;
470 defer constValues.deinit(zcu.gpa);
471 {
472 var it = unwrapped_asm.iterateInputs();
473 while (it.next()) |input| {
474 const constraint = input.constraint;
475 if (!mem.eql(u8, constraint, "I")) {
476 return cg.fail("assembly constraint {q} not supported", .{constraint});
477 }
478 const operand = input.operand.toInterned() orelse {
479 return cg.fail("immediate argument to inline assembly must be compile-time value", .{});
480 };
481 const name = input.name;
482
483 const value = switch (zcu.intern_pool.indexToKey(operand)) {
484 .int => |val| v: {
485 if (val.ty != .u8_type) {
486 return cg.fail("non-u8 type used in inline assembly value: {}", .{val.ty});
487 }
488 break :v val.storage.u64;
489 },
490 else => return cg.fail("non-int operands not supported", .{}),
491 };
492
493 try constValues.put(zcu.gpa, name, @intCast(value));
494 }
495 }
496
497 {
498 var lines = mem.tokenizeScalar(u8, unwrapped_asm.source, '\n');
499 while (lines.next()) |line| {
500 var tokens = mem.tokenizeScalar(u8, line, ' ');
501 // If there's no tokens, then it must be a blank line, so just skip it.
502 const op = tokens.next() orelse continue;
503 const instType = std.meta.stringToEnum(AsmInstType, op) orelse return cg.fail("invalid asm instruction: {q}", .{op});
504 switch (instType) {
505 .LoadI => {
506 const registerString = tokens.next() orelse return cg.fail("missing register for LoadI instruction", .{});
507 const register = std.meta.stringToEnum(Register, registerString) orelse return cg.fail("invalid register: {q}", .{registerString});
508 const value = tokens.next() orelse return cg.fail("missing immediate value for LoadI", .{});
509 const intValue = v: {
510 if (mem.startsWith(u8, value, "%[")) {
511 const name = value[2 .. value.len - 1];
512 break :v constValues.get(name) orelse return cg.fail("constraint name {q} not included in constraints for inline asm", .{name});
513 } else {
514 break :v std.fmt.parseInt(u8, value, 0) catch |err|
515 return cg.fail("invalid LoadI immediate value: {t}", .{err});
516 }
517 };
518 if (register != .OutA) {
519 return cg.fail("TODO: support other variants of LoadI", .{});
520 }
521 try cg.addTagImm8(.load_i_outa, intValue);
522 },
523 else => return cg.fail("TODO: support asm instruction: {t}", .{instType}),
524 }
525 }
526 }
527}
528
529pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
530 try cg.mir_instructions.append(cg.gpa, inst);
531}
532
533pub fn addTag(cg: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
534 try cg.addInst(.{ .tag = tag, .data = .{ .nothing = {} } });
535}
536
537pub fn addTagImm8(cg: *CodeGen, tag: Mir.Inst.Tag, imm8: u8) error{OutOfMemory}!void {
538 try cg.addInst(.{ .tag = tag, .data = .{ .imm8 = imm8 } });
539}
540
541fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } {
542 const zcu = cg.pt.zcu;
543 const func = zcu.funcInfo(cg.func_index);
544 return zcu.codegenFail(func.owner_nav, fmt, args);
545}
546
547fn extraLen(cg: *const CodeGen) u32 {
548 return @intCast(cg.mir_extra.items.len - cg.start_mir_extra_off);
549}
550
551const AsmInstType = enum(u8) {
552 /// Set the memory address high byte to a register value.
553 SetPageReg,
554 /// Set the memory address high byte to a constant value.
555 SetPageI,
556 /// Set the memory address low byte to a register value.
557 SetAddrReg,
558 /// Set the memory address low byte to a constant value.
559 SetAddrI,
560 /// Load a value from a constant address into a register.
561 Load,
562 /// Load a constant value into a register.
563 LoadI,
564 /// Load a value from a constant address (setting low byte only) into a register.
565 LoadP,
566 /// Load a value from the currently set memory address into a register, and increment the address n times.
567 LoadInc,
568 /// Load a value from an offset on the current stack frame into a register.
569 LoadStck,
570 /// Store a value to a constant address from a register.
571 Store,
572 /// Store a constant value into a constant address.
573 StoreI,
574 /// Store a value to a constant address (low byte only) from a register.
575 StoreP,
576 /// Store a value from the currently set memory address from a register, and increment the address n times.
577 StoreInc,
578 /// Store a value to an offset on the current stack frame, from a register.
579 StoreStck,
580 /// Store a value to an offset on the next stack frame, from a register.
581 StoreNStck,
582 /// Store a value to an offset on the previous stack frame, from a register.
583 StorePStck,
584 /// Store a constant value to an offset on the current stack frame.
585 StoreStckI,
586 /// Store a constant value to an offset on the next stack frame.
587 StoreNStckI,
588 /// Store a constant value to an offset on the previous stack frame.
589 StorePStckI,
590 /// Copy a value from one register to another register.
591 Copy,
592 /// Jump to a constant location.
593 Jump,
594 /// Jump to a register A (high byte) + register B (low byte).
595 JumpReg,
596 /// Jump to a location pointed to by memory at the current memory address (high byte first).
597 JumpMem,
598 /// Call a function.
599 Call,
600 /// Return from a function.
601 Return,
602 /// Compare A to a constant value (sets flags, but discards result).
603 CmpI,
604 /// Compare A to a constant value with bitwise AND (sets flags, but discards result).
605 CmpAndI,
606 /// Compare A to a value from memory (sets flags, but discards result).
607 Cmp,
608 /// Compare A to a value in memory with bitwise AND (sets flags, but discards result).
609 CmpAnd,
610 /// Compare A to a value from a register (sets flags, but discards result).
611 CmpReg,
612 /// Compare A to a value from a register with bitwise AND (sets flags, but discards result).
613 CmpAndReg,
614 /// Shift B left by 1.
615 ShiftL,
616 /// Shift B right by 1.
617 ShiftR,
618 /// Rotate B left by 1.
619 RotateL,
620 /// Rotate B right by 1.
621 RotateR,
622 /// Add a constant value to A.
623 AddI,
624 /// Subtract a constant value from A.
625 SubI,
626 /// Bitwise-AND A with a constant value.
627 AndI,
628 /// Add a constant value to A, without updating flags.
629 AddINF,
630 /// Subtract a constant value from A, without updating flags.
631 SubINF,
632 /// Bitwise-AND A with a constant value, without updating flags.
633 AndINF,
634 /// Add register B to A -> A.
635 AccumulateAdd,
636 /// Subtract register B from A -> A.
637 AccumulateSub,
638 /// A & B -> A.
639 AccumulateAnd,
640 /// Bitwise OR B with A -> A.
641 OrI,
642 /// Bitwise OR a constant value with A -> A.
643 XorI,
644 /// Invert register A.
645 Not,
646 /// Add a value from memory to A.
647 Add,
648 /// Subtract a value from memory from A.
649 Sub,
650 /// AND A with a value from memory.
651 And,
652 /// OR A with a value from memory.
653 Or,
654 /// XOR A with a value from memory.
655 Xor,
656 /// No-op.
657 Nop,
658 /// No-op with 1 extra clock cycle.
659 Nop1,
660 /// No-op with 2 extra clock cycles.
661 Nop2,
662 /// Halt - stop the program forever (until reset).
663 Halt,
664};
665
666const Register = enum(u8) {
667 A,
668 B,
669 C,
670 PCnt,
671 MAdr,
672 Stack,
673 OutA,
674 Shift,
675 Swap,
676};
src/codegen/spork8/Mir.zig created+54
...@@ -0,0 +1,54 @@
1const Mir = @This();
2const InternPool = @import("../../InternPool.zig");
3
4const builtin = @import("builtin");
5const std = @import("std");
6const assert = std.debug.assert;
7
8instructions: std.MultiArrayList(Inst).Slice,
9
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_outa = 0x15,
28 /// index
29 jump = 0x68,
30 /// nothing
31 halt = 0xE3,
32 };
33
34 /// All instructions contain a 4-byte payload, which is contained within
35 /// this union. `Tag` determines which union tag is active, as well as
36 /// how to interpret the data within.
37 pub const Data = union {
38 imm8: u8,
39 index: Index,
40 nothing: void,
41
42 comptime {
43 switch (builtin.mode) {
44 .Debug, .ReleaseSafe => {},
45 .ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4),
46 }
47 }
48 };
49};
50
51pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
52 mir.instructions.deinit(gpa);
53 mir.* = undefined;
54}
src/dev.zig+17
...@@ -60,6 +60,10 @@ pub const Env = enum {...@@ -60,6 +60,10 @@ pub const Env = enum {
60 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target loongarch(32/64)-linux --listen=-`60 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target loongarch(32/64)-linux --listen=-`
61 @"loongarch-linux",61 @"loongarch-linux",
6262
63 /// - sema
64 /// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
65 spork8,
66
63 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {67 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
64 return switch (dev_env) {68 return switch (dev_env) {
65 .full => true,69 .full => true,
...@@ -102,6 +106,7 @@ pub const Env = enum {...@@ -102,6 +106,7 @@ pub const Env = enum {
102 .sparc64_backend,106 .sparc64_backend,
103 .spirv_backend,107 .spirv_backend,
104 .loongarch_backend,108 .loongarch_backend,
109 .spork8_backend,
105 .lld_linker,110 .lld_linker,
106 .coff_linker,111 .coff_linker,
107 .coff2_linker,112 .coff2_linker,
...@@ -112,6 +117,7 @@ pub const Env = enum {...@@ -112,6 +117,7 @@ pub const Env = enum {
112 .wasm_linker,117 .wasm_linker,
113 .spirv_linker,118 .spirv_linker,
114 .plan9_linker,119 .plan9_linker,
120 .spork8_linker,
115 .jit_command,121 .jit_command,
116 => true,122 => true,
117 .cc_command,123 .cc_command,
...@@ -239,6 +245,15 @@ pub const Env = enum {...@@ -239,6 +245,15 @@ pub const Env = enum {
239 => true,245 => true,
240 else => Env.sema.supports(feature),246 else => Env.sema.supports(feature),
241 },247 },
248 .spork8 => switch (feature) {
249 .stdio_listen,
250 .incremental,
251 .legalize,
252 .spork8_backend,
253 .spork8_linker,
254 => true,
255 else => Env.sema.supports(feature),
256 },
242 };257 };
243 }258 }
244259
...@@ -303,6 +318,7 @@ pub const Feature = enum {...@@ -303,6 +318,7 @@ pub const Feature = enum {
303 sparc64_backend,318 sparc64_backend,
304 spirv_backend,319 spirv_backend,
305 loongarch_backend,320 loongarch_backend,
321 spork8_backend,
306322
307 lld_linker,323 lld_linker,
308 coff_linker,324 coff_linker,
...@@ -314,6 +330,7 @@ pub const Feature = enum {...@@ -314,6 +330,7 @@ pub const Feature = enum {
314 wasm_linker,330 wasm_linker,
315 spirv_linker,331 spirv_linker,
316 plan9_linker,332 plan9_linker,
333 spork8_linker,
317};334};
318335
319/// Makes the code following the call to this function unreachable if `feature` is disabled.336/// Makes the code following the call to this function unreachable if `feature` is disabled.
src/link.zig+13-1
...@@ -673,6 +673,7 @@ pub const File = struct {...@@ -673,6 +673,7 @@ pub const File = struct {
673 });673 });
674 },674 },
675 .plan9 => unreachable,675 .plan9 => unreachable,
676 .spork8 => dev.check(.spork8_linker),
676 }677 }
677 }678 }
678679
...@@ -750,6 +751,7 @@ pub const File = struct {...@@ -750,6 +751,7 @@ pub const File = struct {
750 },751 },
751 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),752 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
752 .plan9 => unreachable,753 .plan9 => unreachable,
754 .spork8 => dev.check(.spork8_linker),
753 }755 }
754 }756 }
755757
...@@ -1025,6 +1027,7 @@ pub const File = struct {...@@ -1025,6 +1027,7 @@ pub const File = struct {
1025 .spirv => unreachable,1027 .spirv => unreachable,
1026 .wasm => unreachable,1028 .wasm => unreachable,
1027 .plan9 => unreachable,1029 .plan9 => unreachable,
1030 .spork8 => unreachable,
1028 inline else => |tag| {1031 inline else => |tag| {
1029 dev.check(tag.devFeature());1032 dev.check(tag.devFeature());
1030 return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info);1033 return @as(*tag.Type(), @fieldParentPtr("base", base)).getNavVAddr(pt, nav_index, reloc_info);
...@@ -1047,6 +1050,7 @@ pub const File = struct {...@@ -1047,6 +1050,7 @@ pub const File = struct {
1047 .spirv => unreachable,1050 .spirv => unreachable,
1048 .wasm => unreachable,1051 .wasm => unreachable,
1049 .plan9 => unreachable,1052 .plan9 => unreachable,
1053 .spork8 => unreachable,
1050 inline else => |tag| {1054 inline else => |tag| {
1051 dev.check(tag.devFeature());1055 dev.check(tag.devFeature());
1052 return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align);1056 return @as(*tag.Type(), @fieldParentPtr("base", base)).lowerUav(pt, decl_val, decl_align);
...@@ -1064,6 +1068,7 @@ pub const File = struct {...@@ -1064,6 +1068,7 @@ pub const File = struct {
1064 .spirv => unreachable,1068 .spirv => unreachable,
1065 .wasm => unreachable,1069 .wasm => unreachable,
1066 .plan9 => unreachable,1070 .plan9 => unreachable,
1071 .spork8 => unreachable,
1067 inline else => |tag| {1072 inline else => |tag| {
1068 dev.check(tag.devFeature());1073 dev.check(tag.devFeature());
1069 return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info);1074 return @as(*tag.Type(), @fieldParentPtr("base", base)).getUavVAddr(decl_val, reloc_info);
...@@ -1088,6 +1093,7 @@ pub const File = struct {...@@ -1088,6 +1093,7 @@ pub const File = struct {
1088 .spirv,1093 .spirv,
1089 .plan9,1094 .plan9,
1090 .lld,1095 .lld,
1096 .spork8,
1091 => return .unimplemented,1097 => return .unimplemented,
1092 inline else => |tag| {1098 inline else => |tag| {
1093 dev.check(tag.devFeature());1099 dev.check(tag.devFeature());
...@@ -1266,6 +1272,7 @@ pub const File = struct {...@@ -1266,6 +1272,7 @@ pub const File = struct {
1266 c,1272 c,
1267 wasm,1273 wasm,
1268 spirv,1274 spirv,
1275 spork8,
1269 plan9,1276 plan9,
1270 lld,1277 lld,
12711278
...@@ -1280,6 +1287,7 @@ pub const File = struct {...@@ -1280,6 +1287,7 @@ pub const File = struct {
1280 .spirv => SpirV,1287 .spirv => SpirV,
1281 .lld => Lld,1288 .lld => Lld,
1282 .plan9 => comptime unreachable,1289 .plan9 => comptime unreachable,
1290 .spork8 => Spork8,
1283 };1291 };
1284 }1292 }
12851293
...@@ -1293,7 +1301,10 @@ pub const File = struct {...@@ -1293,7 +1301,10 @@ pub const File = struct {
1293 .c => .c,1301 .c => .c,
1294 .spirv => .spirv,1302 .spirv => .spirv,
1295 .hex => @panic("TODO implement hex object format"),1303 .hex => @panic("TODO implement hex object format"),
1296 .raw => @panic("TODO implement raw object format"),1304 // This may seem surprising at first, but with a little massaging, the spork8 linker
1305 // could and probably should be generalized into a "raw linker" which is used to output
1306 // bare machine code for any architecture for which a corresponding backend exists.
1307 .raw => .spork8,
1297 };1308 };
1298 }1309 }
12991310
...@@ -1373,6 +1384,7 @@ pub const File = struct {...@@ -1373,6 +1384,7 @@ pub const File = struct {
1373 pub const Lld = @import("link/Lld.zig");1384 pub const Lld = @import("link/Lld.zig");
1374 pub const C = @import("link/C.zig");1385 pub const C = @import("link/C.zig");
1375 pub const Coff2 = @import("link/Coff.zig");1386 pub const Coff2 = @import("link/Coff.zig");
1387 pub const Spork8 = @import("link/Spork8.zig");
1376 pub const Elf = @import("link/Elf.zig");1388 pub const Elf = @import("link/Elf.zig");
1377 pub const Elf2 = @import("link/Elf2.zig");1389 pub const Elf2 = @import("link/Elf2.zig");
1378 pub const MachO = @import("link/MachO.zig");1390 pub const MachO = @import("link/MachO.zig");
src/link/Spork8.zig created+271
...@@ -0,0 +1,271 @@
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,
25/// All MIR instructions for all Zcu functions.
26mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
27/// Corresponds to `mir_instructions`.
28mir_extra: std.ArrayListUnmanaged(u32) = .empty,
29/// When the key is an enum type, this represents a `@tagName` function.
30zcu_funcs: std.array_hash_map.Auto(InternPool.Index, ZcuFunc) = .empty,
31
32pub fn open(
33 arena: Allocator,
34 comp: *Compilation,
35 emit: Path,
36 options: link.File.OpenOptions,
37) !*Spork8 {
38 // TODO: restore saved linker state, don't truncate the file, and
39 // participate in incremental compilation.
40 return createEmpty(arena, comp, emit, options);
41}
42
43pub fn createEmpty(
44 arena: Allocator,
45 comp: *Compilation,
46 emit: Path,
47 options: link.File.OpenOptions,
48) !*Spork8 {
49 const target = comp.root_mod.resolved_target.result;
50 assert(target.ofmt == .raw);
51 assert(comp.config.output_mode == .Exe);
52 const io = comp.io;
53
54 const spork8 = try arena.create(Spork8);
55 spork8.* = .{
56 .base = .{
57 .tag = .spork8,
58 .comp = comp,
59 .emit = emit,
60 .gc_sections = options.gc_sections orelse true,
61 .print_gc_sections = options.print_gc_sections,
62 .stack_size = options.stack_size orelse switch (target.os.tag) {
63 .freestanding => 1 * 1024 * 1024, // 1 MiB
64 else => 16 * 1024 * 1024, // 16 MiB
65 },
66 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
67 .file = null,
68 .build_id = options.build_id,
69 },
70 };
71 errdefer spork8.base.destroy();
72
73 spork8.base.file = try emit.root_dir.handle.createFile(io, emit.sub_path, .{
74 .truncate = true,
75 .read = true,
76 });
77
78 return spork8;
79}
80
81pub fn deinit(spork8: *Spork8) void {
82 const gpa = spork8.base.comp.gpa;
83 _ = gpa;
84}
85
86pub fn updateFunc(
87 spork8: *Spork8,
88 pt: Zcu.PerThread,
89 func_index: InternPool.Index,
90 any_mir: *const codegen.AnyMir,
91) !void {
92 dev.check(.spork8_backend);
93 // This linker implementation only works with `std.lang.CompilerBackend.zsf_spork8`.
94 const mir = &any_mir.spork8;
95 const zcu = pt.zcu;
96 const gpa = zcu.gpa;
97 const ip = &zcu.intern_pool;
98 const owner_nav = zcu.funcInfo(func_index).owner_nav;
99
100 log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)});
101
102 // For Spork8, we do not lower the MIR to code just yet. That lowering happens during `flush`,
103 // after garbage collection, which can affect function and global indexes, which affects the
104 // LEB integer encoding, which affects the output binary size.
105
106 // However, we do move the MIR into a more efficient in-memory representation, where the arrays
107 // for all functions are packed together rather than keeping them each in their own `Mir`.
108 const mir_instructions_off: u32 = @intCast(spork8.mir_instructions.len);
109 const mir_extra_off: u32 = @intCast(spork8.mir_extra.items.len);
110 {
111 // Copying MultiArrayList data is a little non-trivial. Resize, then memcpy both slices.
112 const old_len = spork8.mir_instructions.len;
113 try spork8.mir_instructions.resize(gpa, old_len + mir.instructions.len);
114 const dest_slice = spork8.mir_instructions.slice().subslice(old_len, mir.instructions.len);
115 const src_slice = mir.instructions;
116 @memcpy(dest_slice.items(.tag), src_slice.items(.tag));
117 @memcpy(dest_slice.items(.data), src_slice.items(.data));
118 }
119 try spork8.mir_extra.appendSlice(gpa, mir.extra);
120
121 try spork8.zcu_funcs.ensureUnusedCapacity(gpa, 1);
122
123 // This converts AIR to MIR but does not yet lower to Spork8 code.
124 spork8.zcu_funcs.putAssumeCapacity(func_index, .{ .function = .{
125 .instructions_off = mir_instructions_off,
126 .instructions_len = @intCast(mir.instructions.len),
127 .extra_off = mir_extra_off,
128 .extra_len = @intCast(mir.extra.len),
129 } });
130}
131
132pub const ZcuFunc = union {
133 function: Function,
134
135 pub const Function = extern struct {
136 /// Index into `Spork8.mir_instructions`.
137 instructions_off: u32,
138 /// This is unused except for as a safety slice bound and could be removed.
139 instructions_len: u32,
140 /// Index into `Spork8.mir_extra`.
141 extra_off: u32,
142 /// This is unused except for as a safety slice bound and could be removed.
143 extra_len: u32,
144 };
145
146 /// Index into `Spork8.zcu_funcs`.
147 /// Note that swapRemove is sometimes performed on `zcu_funcs`.
148 pub const Index = enum(u32) {
149 _,
150
151 pub fn key(i: @This(), spork8: *const Spork8) *InternPool.Index {
152 return &spork8.zcu_funcs.keys()[@backingInt(i)];
153 }
154
155 pub fn value(i: @This(), spork8: *const Spork8) *ZcuFunc {
156 return &spork8.zcu_funcs.values()[@backingInt(i)];
157 }
158 };
159};
160
161// Generate code for the "Nav", storing it in memory to be later written to
162// the file on flush().
163pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
164 _ = spork8;
165 const zcu = pt.zcu;
166 const ip = &zcu.intern_pool;
167 const nav = ip.getNav(nav_index);
168 log.debug("updateNav {f}", .{nav.fqn.fmt(ip)});
169}
170
171pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
172 _ = spork8;
173 _ = pt;
174 _ = ti_id;
175}
176
177pub fn deleteExport(
178 spork8: *Spork8,
179 exported: Zcu.Exported,
180 name: InternPool.NullTerminatedString,
181) void {
182 const zcu = spork8.base.comp.zcu.?;
183 const ip = &zcu.intern_pool;
184 const name_slice = name.toSlice(ip);
185 switch (exported) {
186 .nav => |nav_index| {
187 log.debug("deleteExport '{s}' nav={d}", .{ name_slice, @backingInt(nav_index) });
188 },
189 .uav => |uav_index| {
190 log.debug("deleteExport '{s}' uav={d}", .{ name_slice, @backingInt(uav_index) });
191 },
192 }
193}
194
195pub fn updateExports(
196 spork8: *Spork8,
197 pt: Zcu.PerThread,
198 export_indices: []const Zcu.Export.Index,
199) !void {
200 _ = spork8;
201 const zcu = pt.zcu;
202 const ip = &zcu.intern_pool;
203
204 for (export_indices) |export_idx| {
205 const exp = export_idx.ptr(zcu);
206 const name_slice = exp.opts.name.toSlice(ip);
207 switch (exp.exported) {
208 .nav => |nav_index| {
209 log.debug("updateExports {q} nav={d}", .{ name_slice, @backingInt(nav_index) });
210 },
211 .uav => |uav_index| {
212 log.debug("updateExports {q} uav={d}", .{ name_slice, @backingInt(uav_index) });
213 },
214 }
215 }
216}
217
218pub fn loadInput(spork8: *Spork8, input: link.Input) !void {
219 _ = input;
220 const comp = spork8.base.comp;
221 const diags = &comp.link_diags;
222 return diags.failParse("spork8 does not support linking files together", .{});
223}
224
225pub fn flush(
226 spork8: *Spork8,
227 arena: Allocator,
228 tid: Zcu.PerThread.Id,
229 prog_node: std.Progress.Node,
230) link.Error!void {
231 const sub_prog_node = prog_node.start("Spork8 Flush", 0);
232 defer sub_prog_node.end();
233 const io = spork8.base.comp.io;
234 const diags = &spork8.base.comp.link_diags;
235
236 _ = arena;
237 _ = tid;
238
239 // Finally, write the entire binary into the file.
240 var buffer: [1000]u8 = undefined;
241 var file_writer = spork8.base.file.?.writer(io, &buffer);
242 mirToMC(spork8, &file_writer.interface) catch |err| switch (err) {
243 error.WriteFailed => return diags.fail("failed writing to file: {t}", .{file_writer.err.?}),
244 };
245 file_writer.end() catch |err| switch (err) {
246 error.WriteFailed => return diags.fail("failed writing to file: {t}", .{file_writer.err.?}),
247 else => |e| return diags.fail("failed writing to file: {t}", .{e}),
248 };
249}
250
251fn mirToMC(spork8: *Spork8, w: *Io.Writer) !void {
252 for (spork8.mir_instructions.items(.tag), spork8.mir_instructions.items(.data)) |tag, data| {
253 switch (tag) {
254 .set_page_i => @panic("TODO"),
255 .set_addr_i => @panic("TODO"),
256 .load_i_outa => {
257 try w.writeByte(@backingInt(tag));
258 try w.writeByte(data.imm8);
259 },
260 .jump => @panic("TODO"),
261 .halt => try w.writeByte(@backingInt(tag)),
262 }
263 }
264}
265
266pub fn prelink(spork8: *Spork8, prog_node: std.Progress.Node) link.Error!void {
267 const sub_prog_node = prog_node.start("Spork8 Prelink", 0);
268 defer sub_prog_node.end();
269
270 _ = spork8;
271}
src/target.zig+27-20
...@@ -271,6 +271,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)...@@ -271,6 +271,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
271 .sheb,271 .sheb,
272 .x86_16,272 .x86_16,
273 .xtensaeb,273 .xtensaeb,
274 .spork8,
274 => false,275 => false,
275 };276 };
276}277}
...@@ -395,26 +396,29 @@ pub fn classifyCompilerRtLibName(name: []const u8) CompilerRtClassification {...@@ -395,26 +396,29 @@ pub fn classifyCompilerRtLibName(name: []const u8) CompilerRtClassification {
395}396}
396397
397pub fn hasDebugInfo(target: *const std.Target) bool {398pub fn hasDebugInfo(target: *const std.Target) bool {
398 return switch (target.cpu.arch) {399 return switch (target.ofmt) {
399 // TODO: We should make newer PTX versions depend on older ones so we'd just check `ptx75`.400 .raw, .hex => false,
400 .nvptx, .nvptx64 => target.cpu.hasAny(.nvptx, &.{401 else => switch (target.cpu.arch) {
401 .ptx75,402 // TODO: We should make newer PTX versions depend on older ones so we'd just check `ptx75`.
402 .ptx76,403 .nvptx, .nvptx64 => target.cpu.hasAny(.nvptx, &.{
403 .ptx77,404 .ptx75,
404 .ptx78,405 .ptx76,
405 .ptx80,406 .ptx77,
406 .ptx81,407 .ptx78,
407 .ptx82,408 .ptx80,
408 .ptx83,409 .ptx81,
409 .ptx84,410 .ptx82,
410 .ptx85,411 .ptx83,
411 .ptx86,412 .ptx84,
412 .ptx87,413 .ptx85,
413 .ptx88,414 .ptx86,
414 .ptx90,415 .ptx87,
415 }),416 .ptx88,
416 .bpfel, .bpfeb => false,417 .ptx90,
417 else => true,418 }),
419 .bpfel, .bpfeb => false,
420 else => true,
421 },
418 };422 };
419}423}
420424
...@@ -433,6 +437,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl...@@ -433,6 +437,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
433 }437 }
434 switch (target.cpu.arch) {438 switch (target.cpu.arch) {
435 .spirv32, .spirv64 => return .no,439 .spirv32, .spirv64 => return .no,
440 .spork8 => return .no,
436 // Remove this once https://github.com/ziglang/zig/issues/23714 is fixed441 // Remove this once https://github.com/ziglang/zig/issues/23714 is fixed
437 .amdgcn => return .no,442 .amdgcn => return .no,
438 else => {},443 else => {},
...@@ -445,6 +450,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl...@@ -445,6 +450,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target) enum { no, yes, llvm_onl
445450
446pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only, llvm_lld_only } {451pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only, llvm_lld_only } {
447 switch (target.cpu.arch) {452 switch (target.cpu.arch) {
453 .spork8 => return .no,
448 .spirv32, .spirv64 => return .no,454 .spirv32, .spirv64 => return .no,
449 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed455 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
450 .nvptx, .nvptx64 => return .no,456 .nvptx, .nvptx64 => return .no,
...@@ -929,6 +935,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.lang.CompilerBa...@@ -929,6 +935,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.lang.CompilerBa
929 .wasm32, .wasm64 => .stage2_wasm,935 .wasm32, .wasm64 => .stage2_wasm,
930 .x86 => .stage2_x86,936 .x86 => .stage2_x86,
931 .x86_64 => .stage2_x86_64,937 .x86_64 => .stage2_x86_64,
938 .spork8 => .zsf_spork8,
932 else => .other,939 else => .other,
933 };940 };
934}941}