mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
init spork8 backend
This commit is contained in:
parent
bc2f7c7547
commit
9f5c1038c3
13 changed files with 719 additions and 9 deletions
|
|
@ -104,6 +104,7 @@ pub const Os = struct {
|
|||
.plan9 => arch.plan9Ext(),
|
||||
else => switch (arch) {
|
||||
.wasm32, .wasm64 => ".wasm",
|
||||
.spork8 => ".spork8",
|
||||
else => "",
|
||||
},
|
||||
};
|
||||
|
|
@ -780,6 +781,22 @@ pub const x86 = @import("Target/x86.zig");
|
|||
pub const xcore = @import("Target/xcore.zig");
|
||||
pub const xtensa = @import("Target/xtensa.zig");
|
||||
|
||||
pub const spork8 = struct {
|
||||
pub const Feature = enum {};
|
||||
pub const featureSet = Cpu.Feature.FeatureSetFns(Feature).featureSet;
|
||||
pub const featureSetHas = Cpu.Feature.FeatureSetFns(Feature).featureSetHas;
|
||||
pub const featureSetHasAny = Cpu.Feature.FeatureSetFns(Feature).featureSetHasAny;
|
||||
pub const featureSetHasAll = Cpu.Feature.FeatureSetFns(Feature).featureSetHasAll;
|
||||
|
||||
pub const cpu = struct {
|
||||
pub const generic: Cpu.Model = .{
|
||||
.name = "generic",
|
||||
.llvm_name = null,
|
||||
.features = .empty,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const Abi = enum {
|
||||
none,
|
||||
gnu,
|
||||
|
|
@ -1018,6 +1035,7 @@ pub const ObjectFormat = enum {
|
|||
hex,
|
||||
/// The Mach object format used by macOS and other Apple platforms.
|
||||
macho,
|
||||
spork8,
|
||||
/// The a.out format used by Plan 9 from Bell Labs.
|
||||
plan9,
|
||||
/// Machine code with no metadata.
|
||||
|
|
@ -1038,6 +1056,7 @@ pub const ObjectFormat = enum {
|
|||
.coff => ".obj",
|
||||
.elf, .goff, .macho, .wasm, .xcoff => ".o",
|
||||
.hex => ".ihex",
|
||||
.spork8 => ".spork8",
|
||||
.plan9 => arch.plan9Ext(),
|
||||
.raw => ".bin",
|
||||
.spirv => ".spv",
|
||||
|
|
@ -1054,6 +1073,7 @@ pub const ObjectFormat = enum {
|
|||
else => switch (arch) {
|
||||
.spirv, .spirv32, .spirv64 => .spirv,
|
||||
.wasm32, .wasm64 => .wasm,
|
||||
.spork8 => .spork8,
|
||||
else => .elf,
|
||||
},
|
||||
};
|
||||
|
|
@ -1097,6 +1117,7 @@ pub fn toElfMachine(target: Target) std.elf.EM {
|
|||
.spirv64,
|
||||
.wasm32,
|
||||
.wasm64,
|
||||
.spork8,
|
||||
=> .NONE,
|
||||
};
|
||||
}
|
||||
|
|
@ -1150,6 +1171,7 @@ pub fn toCoffMachine(target: Target) std.coff.MachineType {
|
|||
.xcore,
|
||||
.xtensa,
|
||||
.propeller,
|
||||
.spork8,
|
||||
=> .UNKNOWN,
|
||||
};
|
||||
}
|
||||
|
|
@ -1369,6 +1391,7 @@ pub const Cpu = struct {
|
|||
s390x,
|
||||
sparc,
|
||||
sparc64,
|
||||
spork8,
|
||||
spirv,
|
||||
spirv32,
|
||||
spirv64,
|
||||
|
|
@ -1573,6 +1596,7 @@ pub const Cpu = struct {
|
|||
.sparc64,
|
||||
.lanai,
|
||||
.s390x,
|
||||
.spork8,
|
||||
=> .big,
|
||||
};
|
||||
}
|
||||
|
|
@ -1916,6 +1940,7 @@ pub const Cpu = struct {
|
|||
|
||||
.kalimba,
|
||||
.or1k,
|
||||
.spork8,
|
||||
=> &S.generic_model,
|
||||
};
|
||||
}
|
||||
|
|
@ -2593,6 +2618,7 @@ pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
|
|||
return switch (cpu.arch) {
|
||||
.avr,
|
||||
.msp430,
|
||||
.spork8,
|
||||
=> 16,
|
||||
|
||||
.arc,
|
||||
|
|
@ -3080,7 +3106,7 @@ pub fn cTypeBitSize(target: Target, c_type: CType) u16 {
|
|||
pub fn cTypeAlignment(target: Target, c_type: CType) u16 {
|
||||
// Overrides for unusual alignments
|
||||
switch (target.cpu.arch) {
|
||||
.avr => return 1,
|
||||
.avr, .spork8 => return 1,
|
||||
.x86 => switch (target.os.tag) {
|
||||
.windows, .uefi => switch (c_type) {
|
||||
.longlong, .ulonglong, .double => return 8,
|
||||
|
|
@ -3167,6 +3193,7 @@ pub fn cTypeAlignment(target: Target, c_type: CType) u16 {
|
|||
=> 16,
|
||||
|
||||
.avr,
|
||||
.spork8,
|
||||
=> unreachable, // Handled above.
|
||||
}),
|
||||
);
|
||||
|
|
@ -3267,7 +3294,9 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
|
|||
|
||||
pub fn cMaxIntAlignment(target: std.Target) u16 {
|
||||
return switch (target.cpu.arch) {
|
||||
.avr => 1,
|
||||
.avr,
|
||||
.spork8,
|
||||
=> 1,
|
||||
|
||||
.msp430 => 2,
|
||||
|
||||
|
|
@ -3390,6 +3419,7 @@ pub fn cCallingConvention(target: Target) ?std.builtin.CallingConvention {
|
|||
.amdgcn => .{ .amdgcn_device = .{} },
|
||||
.nvptx, .nvptx64 => .nvptx_device,
|
||||
.spirv, .spirv32, .spirv64 => .spirv_device,
|
||||
.spork8 => .naked,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1110,6 +1110,7 @@ pub const CompilerBackend = enum(u64) {
|
|||
/// The reference implementation self-hosted compiler of Zig, using the
|
||||
/// spirv backend.
|
||||
stage2_spirv64 = 11,
|
||||
stage2_spork8 = 12,
|
||||
|
||||
_,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ comptime {
|
|||
// decls there get run.
|
||||
_ = root;
|
||||
|
||||
if (simplified_logic) {
|
||||
if (builtin.cpu.arch == .spork8) {
|
||||
// always freestanding, even exes
|
||||
} else if (simplified_logic) {
|
||||
if (builtin.output_mode == .Exe) {
|
||||
if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
|
||||
if (!@typeInfo(@TypeOf(root.main)).@"fn".calling_convention.eql(.c)) {
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
|
|||
.spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
|
||||
.hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
|
||||
.raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
|
||||
.spork8 => return std.fmt.allocPrint(allocator, "{s}.spork8", .{root_name}),
|
||||
.plan9 => switch (options.output_mode) {
|
||||
.Exe => return allocator.dupe(u8, root_name),
|
||||
.Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||
.windows, .uefi => .code_view,
|
||||
else => .{ .dwarf = .@"32" },
|
||||
},
|
||||
.spirv, .hex, .raw, .plan9 => .strip,
|
||||
.spirv, .hex, .raw, .plan9, .spork8 => .strip,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3675,6 +3675,8 @@ pub fn atomicPtrAlignment(
|
|||
) AtomicPtrAlignmentError!Alignment {
|
||||
const target = zcu.getTarget();
|
||||
const max_atomic_bits: u16 = switch (target.cpu.arch) {
|
||||
.spork8 => 8,
|
||||
|
||||
.avr,
|
||||
.msp430,
|
||||
=> 16,
|
||||
|
|
@ -4368,6 +4370,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
|
|||
.spirv_fragment, .spirv_vertex => target.os.tag == .vulkan,
|
||||
else => false,
|
||||
},
|
||||
.stage2_spork8 => switch (cc) {
|
||||
.naked => true,
|
||||
else => false,
|
||||
},
|
||||
};
|
||||
if (!backend_ok) return .{ .bad_backend = backend };
|
||||
return .ok;
|
||||
|
|
|
|||
367
src/arch/spork8/CodeGen.zig
Normal file
367
src/arch/spork8/CodeGen.zig
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const CodeGen = @This();
|
||||
const link = @import("../../link.zig");
|
||||
const Spork8 = link.File.Spork8;
|
||||
const Zcu = @import("../../Zcu.zig");
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
const Air = @import("../../Air.zig");
|
||||
const Liveness = @import("../../Liveness.zig");
|
||||
const Mir = @import("Mir.zig");
|
||||
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
gpa: Allocator,
|
||||
spork8: *Spork8,
|
||||
pt: Zcu.PerThread,
|
||||
owner_nav: InternPool.Nav.Index,
|
||||
func_index: InternPool.Index,
|
||||
mir_instructions: *std.MultiArrayList(Mir.Inst),
|
||||
/// Contains extra data for MIR
|
||||
mir_extra: *std.ArrayListUnmanaged(u32),
|
||||
start_mir_extra_off: u32,
|
||||
|
||||
pub const Error = error{
|
||||
OutOfMemory,
|
||||
/// Compiler was asked to operate on a number larger than supported.
|
||||
Overflow,
|
||||
/// Indicates the error is already stored in Zcu `failed_codegen`.
|
||||
CodegenFail,
|
||||
};
|
||||
|
||||
pub const Function = extern struct {
|
||||
/// Index into `Spork8.mir_instructions`.
|
||||
mir_off: u32,
|
||||
/// This is unused except for as a safety slice bound and could be removed.
|
||||
mir_len: u32,
|
||||
/// Index into `Spork8.mir_extra`.
|
||||
mir_extra_off: u32,
|
||||
/// This is unused except for as a safety slice bound and could be removed.
|
||||
mir_extra_len: u32,
|
||||
};
|
||||
|
||||
pub fn function(
|
||||
spork8: *Spork8,
|
||||
pt: Zcu.PerThread,
|
||||
func_index: InternPool.Index,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
) Error!Function {
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const func_info = zcu.funcInfo(func_index);
|
||||
|
||||
var code_gen: CodeGen = .{
|
||||
.gpa = gpa,
|
||||
.pt = pt,
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
.owner_nav = func_info.owner_nav,
|
||||
.spork8 = spork8,
|
||||
.func_index = func_index,
|
||||
.mir_instructions = &spork8.mir_instructions,
|
||||
.mir_extra = &spork8.mir_extra,
|
||||
.start_mir_extra_off = @intCast(spork8.mir_extra.items.len),
|
||||
};
|
||||
defer code_gen.deinit();
|
||||
|
||||
return functionInner(&code_gen) catch |err| switch (err) {
|
||||
error.CodegenFail => return error.CodegenFail,
|
||||
else => |e| return code_gen.fail("failed to generate function: {s}", .{@errorName(e)}),
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(cg: *CodeGen) void {
|
||||
cg.* = undefined;
|
||||
}
|
||||
|
||||
const InnerError = error{
|
||||
CodegenFail,
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
fn functionInner(cg: *CodeGen) InnerError!Function {
|
||||
const spork8 = cg.spork8;
|
||||
|
||||
const start_mir_off: u32 = @intCast(spork8.mir_instructions.len);
|
||||
|
||||
// Generate MIR for function body
|
||||
try cg.genBody(cg.air.getMainBody());
|
||||
|
||||
return .{
|
||||
.mir_off = start_mir_off,
|
||||
.mir_len = @intCast(spork8.mir_instructions.len - start_mir_off),
|
||||
.mir_extra_off = cg.start_mir_extra_off,
|
||||
.mir_extra_len = cg.extraLen(),
|
||||
};
|
||||
}
|
||||
|
||||
fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
const zcu = cg.pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
for (body) |inst| {
|
||||
if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
|
||||
try cg.genInst(inst);
|
||||
}
|
||||
}
|
||||
|
||||
fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const air_tags = cg.air.instructions.items(.tag);
|
||||
return switch (air_tags[@intFromEnum(inst)]) {
|
||||
.inferred_alloc, .inferred_alloc_comptime => unreachable,
|
||||
|
||||
.unreach => cg.airUnreachable(inst),
|
||||
|
||||
.add,
|
||||
.add_sat,
|
||||
.add_wrap,
|
||||
.sub,
|
||||
.sub_sat,
|
||||
.sub_wrap,
|
||||
.mul,
|
||||
.mul_sat,
|
||||
.mul_wrap,
|
||||
.div_float,
|
||||
.div_exact,
|
||||
.div_trunc,
|
||||
.div_floor,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
.rem,
|
||||
.mod,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shl_sat,
|
||||
.shr,
|
||||
.shr_exact,
|
||||
.xor,
|
||||
.max,
|
||||
.min,
|
||||
.mul_add,
|
||||
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.tan,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
.neg,
|
||||
|
||||
.abs,
|
||||
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.mul_with_overflow,
|
||||
|
||||
.clz,
|
||||
.ctz,
|
||||
|
||||
.cmp_eq,
|
||||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_lte,
|
||||
.cmp_lt,
|
||||
.cmp_neq,
|
||||
|
||||
.cmp_vector,
|
||||
.cmp_lt_errors_len,
|
||||
|
||||
.array_elem_val,
|
||||
.array_to_slice,
|
||||
.alloc,
|
||||
.arg,
|
||||
.bitcast,
|
||||
.block,
|
||||
.trap,
|
||||
.breakpoint,
|
||||
.br,
|
||||
.repeat,
|
||||
.switch_dispatch,
|
||||
.cond_br,
|
||||
.intcast,
|
||||
.fptrunc,
|
||||
.fpext,
|
||||
.int_from_float,
|
||||
.float_from_int,
|
||||
.get_union_tag,
|
||||
|
||||
.@"try",
|
||||
.try_cold,
|
||||
.try_ptr,
|
||||
.try_ptr_cold,
|
||||
|
||||
.dbg_stmt,
|
||||
.dbg_empty_stmt,
|
||||
.dbg_inline_block,
|
||||
.dbg_var_ptr,
|
||||
.dbg_var_val,
|
||||
.dbg_arg_inline,
|
||||
|
||||
.call,
|
||||
.call_always_tail,
|
||||
.call_never_tail,
|
||||
.call_never_inline,
|
||||
|
||||
.is_err,
|
||||
.is_non_err,
|
||||
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
.is_null_ptr,
|
||||
.is_non_null_ptr,
|
||||
|
||||
.load,
|
||||
.loop,
|
||||
.memset,
|
||||
.memset_safe,
|
||||
.not,
|
||||
.optional_payload,
|
||||
.optional_payload_ptr,
|
||||
.optional_payload_ptr_set,
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
.ptr_elem_ptr,
|
||||
.ptr_elem_val,
|
||||
.ret,
|
||||
.ret_safe,
|
||||
.ret_ptr,
|
||||
.ret_load,
|
||||
.splat,
|
||||
.select,
|
||||
.shuffle,
|
||||
.reduce,
|
||||
.aggregate_init,
|
||||
.union_init,
|
||||
.prefetch,
|
||||
.popcount,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
|
||||
.slice,
|
||||
.slice_len,
|
||||
.slice_elem_val,
|
||||
.slice_elem_ptr,
|
||||
.slice_ptr,
|
||||
.ptr_slice_len_ptr,
|
||||
.ptr_slice_ptr_ptr,
|
||||
.store,
|
||||
.store_safe,
|
||||
|
||||
.set_union_tag,
|
||||
.struct_field_ptr,
|
||||
.struct_field_ptr_index_0,
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.struct_field_val,
|
||||
.field_parent_ptr,
|
||||
|
||||
.switch_br,
|
||||
.loop_switch_br,
|
||||
.trunc,
|
||||
|
||||
.wrap_optional,
|
||||
.unwrap_errunion_payload,
|
||||
.unwrap_errunion_payload_ptr,
|
||||
.unwrap_errunion_err,
|
||||
.unwrap_errunion_err_ptr,
|
||||
.wrap_errunion_payload,
|
||||
.wrap_errunion_err,
|
||||
.errunion_payload_ptr_set,
|
||||
.error_name,
|
||||
|
||||
.wasm_memory_size,
|
||||
.wasm_memory_grow,
|
||||
|
||||
.memcpy,
|
||||
|
||||
.ret_addr,
|
||||
.tag_name,
|
||||
|
||||
.error_set_has_value,
|
||||
.frame_addr,
|
||||
|
||||
.assembly,
|
||||
.is_err_ptr,
|
||||
.is_non_err_ptr,
|
||||
|
||||
.err_return_trace,
|
||||
.set_err_return_trace,
|
||||
.save_err_return_trace_index,
|
||||
.is_named_enum_value,
|
||||
.addrspace_cast,
|
||||
.vector_store_elem,
|
||||
.c_va_arg,
|
||||
.c_va_copy,
|
||||
.c_va_end,
|
||||
.c_va_start,
|
||||
.memmove,
|
||||
|
||||
.atomic_load,
|
||||
.atomic_store_unordered,
|
||||
.atomic_store_monotonic,
|
||||
.atomic_store_release,
|
||||
.atomic_store_seq_cst,
|
||||
.atomic_rmw,
|
||||
.cmpxchg_weak,
|
||||
.cmpxchg_strong,
|
||||
|
||||
.add_optimized,
|
||||
.sub_optimized,
|
||||
.mul_optimized,
|
||||
.div_float_optimized,
|
||||
.div_trunc_optimized,
|
||||
.div_floor_optimized,
|
||||
.div_exact_optimized,
|
||||
.rem_optimized,
|
||||
.mod_optimized,
|
||||
.neg_optimized,
|
||||
.cmp_lt_optimized,
|
||||
.cmp_lte_optimized,
|
||||
.cmp_eq_optimized,
|
||||
.cmp_gte_optimized,
|
||||
.cmp_gt_optimized,
|
||||
.cmp_neq_optimized,
|
||||
.cmp_vector_optimized,
|
||||
.reduce_optimized,
|
||||
.int_from_float_optimized,
|
||||
.add_safe,
|
||||
.sub_safe,
|
||||
.mul_safe,
|
||||
.intcast_safe,
|
||||
=> |tag| return cg.fail("TODO: implement spork8 inst: {s}", .{@tagName(tag)}),
|
||||
|
||||
.work_item_id,
|
||||
.work_group_size,
|
||||
.work_group_id,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
_ = cg;
|
||||
_ = inst;
|
||||
}
|
||||
|
||||
fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
|
||||
const zcu = cg.pt.zcu;
|
||||
const func = zcu.funcInfo(cg.func_index);
|
||||
return zcu.codegenFail(func.owner_nav, fmt, args);
|
||||
}
|
||||
|
||||
fn extraLen(cg: *const CodeGen) u32 {
|
||||
return @intCast(cg.mir_extra.items.len - cg.start_mir_extra_off);
|
||||
}
|
||||
46
src/arch/spork8/Mir.zig
Normal file
46
src/arch/spork8/Mir.zig
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
const Mir = @This();
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
instruction_tags: []const Inst.Tag,
|
||||
instruction_datas: []const Inst.Data,
|
||||
extra: []const u32,
|
||||
|
||||
pub const Inst = struct {
|
||||
tag: Tag,
|
||||
data: Data,
|
||||
|
||||
/// The position of a given MIR isntruction with the instruction list.
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
pub const Tag = enum(u8) {
|
||||
/// imm8
|
||||
set_page_i = 0x04,
|
||||
/// imm8
|
||||
set_addr_i = 0x09,
|
||||
/// imm8
|
||||
load_i = 0x10,
|
||||
/// index
|
||||
jump,
|
||||
};
|
||||
|
||||
/// All instructions contain a 4-byte payload, which is contained within
|
||||
/// this union. `Tag` determines which union tag is active, as well as
|
||||
/// how to interpret the data within.
|
||||
pub const Data = union {
|
||||
imm8: u8,
|
||||
index: Index,
|
||||
|
||||
comptime {
|
||||
switch (builtin.mode) {
|
||||
.Debug, .ReleaseSafe => {},
|
||||
.ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4),
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -100,6 +100,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
|
|||
.kalimba,
|
||||
.or1k,
|
||||
.propeller,
|
||||
.spork8,
|
||||
=> unreachable, // Gated by hasLlvmSupport().
|
||||
};
|
||||
|
||||
|
|
@ -457,6 +458,7 @@ pub fn dataLayout(target: std.Target) []const u8 {
|
|||
.kalimba,
|
||||
.or1k,
|
||||
.propeller,
|
||||
.spork8,
|
||||
=> unreachable, // Gated by hasLlvmSupport().
|
||||
};
|
||||
}
|
||||
|
|
|
|||
16
src/dev.zig
16
src/dev.zig
|
|
@ -34,6 +34,10 @@ pub const Env = enum {
|
|||
/// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
|
||||
wasm,
|
||||
|
||||
/// - sema
|
||||
/// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
|
||||
spork8,
|
||||
|
||||
pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
|
||||
return switch (dev_env) {
|
||||
.full => true,
|
||||
|
|
@ -73,6 +77,7 @@ pub const Env = enum {
|
|||
.riscv64_backend,
|
||||
.sparc64_backend,
|
||||
.spirv64_backend,
|
||||
.spork8_backend,
|
||||
.lld_linker,
|
||||
.coff_linker,
|
||||
.elf_linker,
|
||||
|
|
@ -83,6 +88,7 @@ pub const Env = enum {
|
|||
.plan9_linker,
|
||||
.goff_linker,
|
||||
.xcoff_linker,
|
||||
.spork8_linker,
|
||||
=> true,
|
||||
.cc_command,
|
||||
.translate_c_command,
|
||||
|
|
@ -158,6 +164,14 @@ pub const Env = enum {
|
|||
=> true,
|
||||
else => Env.sema.supports(feature),
|
||||
},
|
||||
.spork8 => switch (feature) {
|
||||
.stdio_listen,
|
||||
.incremental,
|
||||
.spork8_backend,
|
||||
.spork8_linker,
|
||||
=> true,
|
||||
else => Env.sema.supports(feature),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -219,6 +233,7 @@ pub const Feature = enum {
|
|||
riscv64_backend,
|
||||
sparc64_backend,
|
||||
spirv64_backend,
|
||||
spork8_backend,
|
||||
|
||||
lld_linker,
|
||||
coff_linker,
|
||||
|
|
@ -230,6 +245,7 @@ pub const Feature = enum {
|
|||
plan9_linker,
|
||||
goff_linker,
|
||||
xcoff_linker,
|
||||
spork8_linker,
|
||||
};
|
||||
|
||||
/// Makes the code following the call to this function unreachable if `feature` is disabled.
|
||||
|
|
|
|||
|
|
@ -598,6 +598,7 @@ pub const File = struct {
|
|||
});
|
||||
},
|
||||
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
|
||||
.spork8 => dev.check(.spork8_linker),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -671,6 +672,7 @@ pub const File = struct {
|
|||
}
|
||||
},
|
||||
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
|
||||
.spork8 => dev.check(.spork8_linker),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1245,6 +1247,7 @@ pub const File = struct {
|
|||
c,
|
||||
wasm,
|
||||
spirv,
|
||||
spork8,
|
||||
plan9,
|
||||
goff,
|
||||
xcoff,
|
||||
|
|
@ -1260,6 +1263,7 @@ pub const File = struct {
|
|||
.plan9 => Plan9,
|
||||
.goff => Goff,
|
||||
.xcoff => Xcoff,
|
||||
.spork8 => Spork8,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1274,6 +1278,7 @@ pub const File = struct {
|
|||
.spirv => .spirv,
|
||||
.goff => .goff,
|
||||
.xcoff => .xcoff,
|
||||
.spork8 => .spork8,
|
||||
.hex => @panic("TODO implement hex object format"),
|
||||
.raw => @panic("TODO implement raw object format"),
|
||||
};
|
||||
|
|
@ -1373,6 +1378,7 @@ pub const File = struct {
|
|||
|
||||
pub const C = @import("link/C.zig");
|
||||
pub const Coff = @import("link/Coff.zig");
|
||||
pub const Spork8 = @import("link/Spork8.zig");
|
||||
pub const Plan9 = @import("link/Plan9.zig");
|
||||
pub const Elf = @import("link/Elf.zig");
|
||||
pub const MachO = @import("link/MachO.zig");
|
||||
|
|
|
|||
228
src/link/Spork8.zig
Normal file
228
src/link/Spork8.zig
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
const Spork8 = @This();
|
||||
const builtin = @import("builtin");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const Path = std.Build.Cache.Path;
|
||||
const log = std.log.scoped(.link);
|
||||
|
||||
const Air = @import("../Air.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Zcu = @import("../Zcu.zig");
|
||||
const CodeGen = @import("../arch/spork8/CodeGen.zig");
|
||||
const Mir = @import("../arch/spork8/Mir.zig");
|
||||
const link = @import("../link.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const dev = @import("../dev.zig");
|
||||
const Value = @import("../Value.zig");
|
||||
|
||||
base: link.File,
|
||||
funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, CodeGen.Function) = .empty,
|
||||
/// All MIR instructions for all Zcu functions.
|
||||
mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
|
||||
/// Corresponds to `mir_instructions`.
|
||||
mir_extra: std.ArrayListUnmanaged(u32) = .empty,
|
||||
|
||||
pub fn open(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Spork8 {
|
||||
// TODO: restore saved linker state, don't truncate the file, and
|
||||
// participate in incremental compilation.
|
||||
return createEmpty(arena, comp, emit, options);
|
||||
}
|
||||
|
||||
pub fn createEmpty(
|
||||
arena: Allocator,
|
||||
comp: *Compilation,
|
||||
emit: Path,
|
||||
options: link.File.OpenOptions,
|
||||
) !*Spork8 {
|
||||
const target = comp.root_mod.resolved_target.result;
|
||||
assert(target.ofmt == .spork8);
|
||||
assert(comp.config.output_mode == .Exe);
|
||||
|
||||
const spork8 = try arena.create(Spork8);
|
||||
spork8.* = .{
|
||||
.base = .{
|
||||
.tag = .spork8,
|
||||
.comp = comp,
|
||||
.emit = emit,
|
||||
.zcu_object_sub_path = null,
|
||||
.gc_sections = options.gc_sections orelse true,
|
||||
.print_gc_sections = options.print_gc_sections,
|
||||
.stack_size = options.stack_size orelse switch (target.os.tag) {
|
||||
.freestanding => 1 * 1024 * 1024, // 1 MiB
|
||||
else => 16 * 1024 * 1024, // 16 MiB
|
||||
},
|
||||
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
|
||||
.file = null,
|
||||
.disable_lld_caching = options.disable_lld_caching,
|
||||
.build_id = options.build_id,
|
||||
},
|
||||
};
|
||||
errdefer spork8.base.destroy();
|
||||
|
||||
spork8.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
|
||||
.truncate = true,
|
||||
.read = true,
|
||||
});
|
||||
|
||||
return spork8;
|
||||
}
|
||||
|
||||
pub fn deinit(spork8: *Spork8) void {
|
||||
const gpa = spork8.base.comp.gpa;
|
||||
_ = gpa;
|
||||
}
|
||||
|
||||
pub fn updateFunc(
|
||||
spork8: *Spork8,
|
||||
pt: Zcu.PerThread,
|
||||
func_index: InternPool.Index,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .spork8) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
|
||||
dev.check(.spork8_backend);
|
||||
|
||||
const zcu = pt.zcu;
|
||||
const gpa = spork8.base.comp.gpa;
|
||||
|
||||
const ip = &zcu.intern_pool;
|
||||
const owner_nav = zcu.funcInfo(func_index).owner_nav;
|
||||
log.debug("updateFunc {}", .{ip.getNav(owner_nav).fqn.fmt(ip)});
|
||||
|
||||
const function = try CodeGen.function(spork8, pt, func_index, air, liveness);
|
||||
try spork8.funcs.put(gpa, func_index, function);
|
||||
}
|
||||
|
||||
// Generate code for the "Nav", storing it in memory to be later written to
|
||||
// the file on flush().
|
||||
pub fn updateNav(spork8: *Spork8, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
|
||||
_ = spork8;
|
||||
if (build_options.skip_non_native and builtin.object_format != .spork8) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
|
||||
const nav_init, const chased_nav_index = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||
.func => return, // global const which is a function alias
|
||||
.@"extern" => |ext| {
|
||||
_ = ext;
|
||||
@panic("TODO updateNav extern func");
|
||||
},
|
||||
.variable => |variable| .{ variable.init, variable.owner_nav },
|
||||
else => .{ nav.status.fully_resolved.val, nav_index },
|
||||
};
|
||||
log.debug("updateNav {} {d}", .{ nav.fqn.fmt(ip), chased_nav_index });
|
||||
|
||||
if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateLineNumber(spork8: *Spork8, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
|
||||
_ = spork8;
|
||||
_ = pt;
|
||||
_ = ti_id;
|
||||
}
|
||||
|
||||
pub fn deleteExport(
|
||||
spork8: *Spork8,
|
||||
exported: Zcu.Exported,
|
||||
name: InternPool.NullTerminatedString,
|
||||
) void {
|
||||
const zcu = spork8.base.comp.zcu.?;
|
||||
const ip = &zcu.intern_pool;
|
||||
const name_slice = name.toSlice(ip);
|
||||
switch (exported) {
|
||||
.nav => |nav_index| {
|
||||
log.debug("deleteExport '{s}' nav={d}", .{ name_slice, @intFromEnum(nav_index) });
|
||||
},
|
||||
.uav => |uav_index| {
|
||||
log.debug("deleteExport '{s}' uav={d}", .{ name_slice, @intFromEnum(uav_index) });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateExports(
|
||||
spork8: *Spork8,
|
||||
pt: Zcu.PerThread,
|
||||
exported: Zcu.Exported,
|
||||
export_indices: []const Zcu.Export.Index,
|
||||
) !void {
|
||||
_ = spork8;
|
||||
if (build_options.skip_non_native and builtin.object_format != .spork8) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
for (export_indices) |export_idx| {
|
||||
const exp = export_idx.ptr(zcu);
|
||||
const name_slice = exp.opts.name.toSlice(ip);
|
||||
switch (exported) {
|
||||
.nav => |nav_index| {
|
||||
log.debug("updateExports '{s}' nav={d}", .{ name_slice, @intFromEnum(nav_index) });
|
||||
},
|
||||
.uav => |uav_index| {
|
||||
log.debug("updateExports '{s}' uav={d}", .{ name_slice, @intFromEnum(uav_index) });
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loadInput(spork8: *Spork8, input: link.Input) !void {
|
||||
_ = input;
|
||||
const comp = spork8.base.comp;
|
||||
const diags = &comp.link_diags;
|
||||
return diags.failParse("spork8 does not support linking files together", .{});
|
||||
}
|
||||
|
||||
pub fn flush(
|
||||
spork8: *Spork8,
|
||||
arena: Allocator,
|
||||
tid: Zcu.PerThread.Id,
|
||||
prog_node: std.Progress.Node,
|
||||
) link.File.FlushError!void {
|
||||
return spork8.flushModule(arena, tid, prog_node);
|
||||
}
|
||||
|
||||
pub fn prelink(spork8: *Spork8, prog_node: std.Progress.Node) link.File.FlushError!void {
|
||||
const sub_prog_node = prog_node.start("Spork8 Prelink", 0);
|
||||
defer sub_prog_node.end();
|
||||
|
||||
_ = spork8;
|
||||
}
|
||||
|
||||
pub fn flushModule(
|
||||
spork8: *Spork8,
|
||||
arena: Allocator,
|
||||
tid: Zcu.PerThread.Id,
|
||||
prog_node: std.Progress.Node,
|
||||
) link.File.FlushError!void {
|
||||
// The goal is to never use this because it's only needed if we need to
|
||||
// write to InternPool, but flushModule is too late to be writing to the
|
||||
// InternPool.
|
||||
_ = tid;
|
||||
const comp = spork8.base.comp;
|
||||
const diags = &comp.link_diags;
|
||||
|
||||
const sub_prog_node = prog_node.start("Spork8 Flush", 0);
|
||||
defer sub_prog_node.end();
|
||||
|
||||
_ = arena;
|
||||
|
||||
return diags.fail("TODO implement flushModule for spork8", .{});
|
||||
}
|
||||
|
|
@ -133,6 +133,7 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool {
|
|||
// LLVM does not support these object formats:
|
||||
.c,
|
||||
.plan9,
|
||||
.spork8,
|
||||
=> return false,
|
||||
|
||||
.coff,
|
||||
|
|
@ -200,6 +201,7 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool {
|
|||
.kalimba,
|
||||
.or1k,
|
||||
.propeller,
|
||||
.spork8,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
|
|
@ -323,6 +325,7 @@ pub fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool, have_llvm: bool
|
|||
else => {},
|
||||
}
|
||||
switch (target.cpu.arch) {
|
||||
.spork8 => return false,
|
||||
.spirv, .spirv32, .spirv64 => return false,
|
||||
// Remove this once https://github.com/ziglang/zig/issues/23714 is fixed
|
||||
.amdgcn => return false,
|
||||
|
|
@ -336,12 +339,13 @@ pub fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool, have_llvm: bool
|
|||
}
|
||||
|
||||
pub fn canBuildLibUbsanRt(target: std.Target) bool {
|
||||
switch (target.cpu.arch) {
|
||||
.spirv, .spirv32, .spirv64 => return false,
|
||||
return switch (target.cpu.arch) {
|
||||
.spork8 => false,
|
||||
.spirv, .spirv32, .spirv64 => false,
|
||||
// Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
|
||||
.nvptx, .nvptx64 => return false,
|
||||
else => return true,
|
||||
}
|
||||
.nvptx, .nvptx64 => false,
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hasRedZone(target: std.Target) bool {
|
||||
|
|
@ -804,6 +808,7 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
|
|||
.riscv64 => .stage2_riscv64,
|
||||
.sparc64 => .stage2_sparc64,
|
||||
.spirv64 => .stage2_spirv64,
|
||||
.spork8 => .stage2_spork8,
|
||||
else => .other,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue