mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
SPIR-V: Linking and codegen setup
This commit is contained in:
parent
ab607d455e
commit
b2b87b5900
@ -1622,7 +1622,7 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
|
||||
// in `Decl` to notice that the line number did not change.
|
||||
self.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
|
||||
},
|
||||
.c, .wasm => {},
|
||||
.c, .wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1855,6 +1855,7 @@ fn allocateNewDecl(
|
||||
.macho => .{ .macho = link.File.MachO.TextBlock.empty },
|
||||
.c => .{ .c = link.File.C.DeclBlock.empty },
|
||||
.wasm => .{ .wasm = {} },
|
||||
.spirv => .{ .spirv = {} },
|
||||
},
|
||||
.fn_link = switch (mod.comp.bin_file.tag) {
|
||||
.coff => .{ .coff = {} },
|
||||
@ -1862,6 +1863,7 @@ fn allocateNewDecl(
|
||||
.macho => .{ .macho = link.File.MachO.SrcFn.empty },
|
||||
.c => .{ .c = link.File.C.FnBlock.empty },
|
||||
.wasm => .{ .wasm = null },
|
||||
.spirv => .{ .spirv = .{} },
|
||||
},
|
||||
.generation = 0,
|
||||
.is_pub = false,
|
||||
@ -1959,6 +1961,7 @@ pub fn analyzeExport(
|
||||
.macho => .{ .macho = link.File.MachO.Export{} },
|
||||
.c => .{ .c = {} },
|
||||
.wasm => .{ .wasm = {} },
|
||||
.spirv => .{ .spirv = {} },
|
||||
},
|
||||
.owner_decl = owner_decl,
|
||||
.exported_decl = exported_decl,
|
||||
|
||||
22
src/codegen/spirv.zig
Normal file
22
src/codegen/spirv.zig
Normal file
@ -0,0 +1,22 @@
|
||||
const std = @import("std");
|
||||
const spec = @import("spirv/spec.zig");
|
||||
const Module = @import("../Module.zig");
|
||||
const Decl = Module.Decl;
|
||||
|
||||
pub const SPIRVModule = struct {
|
||||
// TODO: Also use a free list.
|
||||
next_id: u32 = 0,
|
||||
|
||||
pub fn allocId(self: *SPIRVModule) u32 {
|
||||
defer self.next_id += 1;
|
||||
return self.next_id;
|
||||
}
|
||||
|
||||
pub fn idBound(self: *SPIRVModule) u32 {
|
||||
return self.next_id;
|
||||
}
|
||||
|
||||
pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {
|
||||
|
||||
}
|
||||
};
|
||||
29
src/link.zig
29
src/link.zig
@ -142,7 +142,7 @@ pub const File = struct {
|
||||
macho: MachO.SrcFn,
|
||||
c: C.FnBlock,
|
||||
wasm: ?Wasm.FnData,
|
||||
spirv: void,
|
||||
spirv: SpirV.FnData,
|
||||
};
|
||||
|
||||
pub const Export = union {
|
||||
@ -180,7 +180,7 @@ pub const File = struct {
|
||||
.macho => &(try MachO.createEmpty(allocator, options)).base,
|
||||
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
|
||||
.c => unreachable, // Reported error earlier.
|
||||
.spirv => return error.SpirVObjectFormatUnimplemented,
|
||||
.spirv => &(try SpirV.createEmpty(allocator, options)).base,
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
.raw => return error.RawObjectFormatUnimplemented,
|
||||
};
|
||||
@ -196,7 +196,7 @@ pub const File = struct {
|
||||
.macho => &(try MachO.createEmpty(allocator, options)).base,
|
||||
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
|
||||
.c => unreachable, // Reported error earlier.
|
||||
.spirv => return error.SpirVObjectFormatUnimplemented,
|
||||
.spirv => &(try SpirV.createEmpty(allocator, options)).base,
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
.raw => return error.RawObjectFormatUnimplemented,
|
||||
};
|
||||
@ -212,7 +212,7 @@ pub const File = struct {
|
||||
.macho => &(try MachO.openPath(allocator, sub_path, options)).base,
|
||||
.wasm => &(try Wasm.openPath(allocator, sub_path, options)).base,
|
||||
.c => &(try C.openPath(allocator, sub_path, options)).base,
|
||||
.spirv => return error.SpirVObjectFormatUnimplemented,
|
||||
.spirv => &(try SpirV.openPath(allocator, sub_path, options)).base,
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
.raw => return error.RawObjectFormatUnimplemented,
|
||||
};
|
||||
@ -242,7 +242,7 @@ pub const File = struct {
|
||||
.mode = determineMode(base.options),
|
||||
});
|
||||
},
|
||||
.c, .wasm => {},
|
||||
.c, .wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +287,7 @@ pub const File = struct {
|
||||
f.close();
|
||||
base.file = null;
|
||||
},
|
||||
.c, .wasm => {},
|
||||
.c, .wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,6 +300,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl),
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,7 +310,7 @@ pub const File = struct {
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),
|
||||
.wasm => {},
|
||||
.wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,7 +322,7 @@ pub const File = struct {
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
|
||||
.wasm => {},
|
||||
.wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,6 +369,11 @@ pub const File = struct {
|
||||
parent.deinit();
|
||||
base.allocator.destroy(parent);
|
||||
},
|
||||
.spirv => {
|
||||
const parent = @fieldParentPtr(SpirV, "base", base);
|
||||
parent.deinit();
|
||||
base.allocator.destroy(parent);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,6 +407,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).flush(comp),
|
||||
.c => return @fieldParentPtr(C, "base", base).flush(comp),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp),
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,6 +420,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).flushModule(comp),
|
||||
.c => return @fieldParentPtr(C, "base", base).flushModule(comp),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp),
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,6 +432,7 @@ pub const File = struct {
|
||||
.macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl),
|
||||
.c => @fieldParentPtr(C, "base", base).freeDecl(decl),
|
||||
.wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl),
|
||||
.spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl),
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +442,7 @@ pub const File = struct {
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).error_flags,
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).error_flags,
|
||||
.c => return .{ .no_entry_point_found = false },
|
||||
.wasm => return ErrorFlags{},
|
||||
.wasm, .spirv => return ErrorFlags{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,6 +460,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl, exports),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl, exports),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl, exports),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl, exports),
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,6 +471,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl),
|
||||
.c => unreachable,
|
||||
.wasm => unreachable,
|
||||
.spirv => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
131
src/link/SpirV.zig
Normal file
131
src/link/SpirV.zig
Normal file
@ -0,0 +1,131 @@
|
||||
const SpirV = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const link = @import("../link.zig");
|
||||
const codegen = @import("../codegen/spirv.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const build_options = @import("build_options");
|
||||
const spec = @import("../codegen/spirv/spec.zig");
|
||||
|
||||
pub const FnData = struct {
|
||||
id: ?u32 = null,
|
||||
code: std.ArrayListUnmanaged(u32) = .{},
|
||||
};
|
||||
|
||||
base: link.File,
|
||||
|
||||
// TODO: Does this file need to support multiple independent modules?
|
||||
spirv_module: codegen.SPIRVModule = .{},
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*SpirV {
|
||||
const spirv = try gpa.create(SpirV);
|
||||
spirv.* = .{
|
||||
.base = .{
|
||||
.tag = .spirv,
|
||||
.options = options,
|
||||
.file = null,
|
||||
.allocator = gpa,
|
||||
},
|
||||
};
|
||||
return spirv;
|
||||
}
|
||||
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*SpirV {
|
||||
assert(options.object_format == .spirv);
|
||||
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.
|
||||
if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
|
||||
|
||||
// TODO: read the file and keep vaild parts instead of truncating
|
||||
const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
|
||||
errdefer file.close();
|
||||
|
||||
const spirv = try createEmpty(allocator, options);
|
||||
errdefer spirv.base.destroy();
|
||||
|
||||
spirv.base.file = file;
|
||||
return spirv;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *SpirV) void {
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const fn_data = &decl.fn_link.spirv;
|
||||
if (fn_data.id == null) {
|
||||
fn_data.id = self.spirv_module.allocId();
|
||||
}
|
||||
|
||||
var managed_code = fn_data.code.toManaged(self.base.allocator);
|
||||
managed_code.items.len = 0;
|
||||
|
||||
try self.spirv_module.genDecl(fn_data.id.?, &managed_code, decl);
|
||||
fn_data.code = managed_code.toUnmanaged();
|
||||
|
||||
// Free excess allocated memory for this Decl.
|
||||
fn_data.code.shrinkAndFree(self.base.allocator, fn_data.code.items.len);
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
self: *SpirV,
|
||||
module: *Module,
|
||||
decl: *const Module.Decl,
|
||||
exports: []const *Module.Export,
|
||||
) !void {}
|
||||
|
||||
pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {
|
||||
decl.fn_link.spirv.code.deinit(self.base.allocator);
|
||||
decl.fn_link.spirv = undefined;
|
||||
}
|
||||
|
||||
pub fn flush(self: *SpirV, comp: *Compilation) !void {
|
||||
if (build_options.have_llvm and self.base.options.use_lld) {
|
||||
return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
|
||||
} else {
|
||||
return self.flushModule(comp);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const module = self.base.options.module.?;
|
||||
|
||||
const file = self.base.file.?;
|
||||
var bw = std.io.bufferedWriter(file.writer());
|
||||
const writer = bw.writer();
|
||||
|
||||
// Header
|
||||
// SPIR-V files support both little and big endian words. The actual format is disambiguated by
|
||||
// the magic number. This backend uses little endian.
|
||||
try writer.writeIntLittle(u32, spec.magic_number);
|
||||
try writer.writeIntLittle(u32, (spec.version.major << 16) | (spec.version.minor) << 8);
|
||||
try writer.writeIntLittle(u32, 0); // TODO: Register Zig compiler magic number.
|
||||
try writer.writeIntLittle(u32, self.spirv_module.idBound());
|
||||
try writer.writeIntLittle(u32, 0); // Schema.
|
||||
|
||||
// Declarations
|
||||
for (module.decl_table.items()) |entry| {
|
||||
const decl = entry.value;
|
||||
switch (decl.typed_value) {
|
||||
.most_recent => |tvm| {
|
||||
const fn_data = &decl.fn_link.spirv;
|
||||
for (fn_data.code.items) |word| {
|
||||
try writer.writeIntLittle(u32, word);
|
||||
}
|
||||
},
|
||||
.never_succeeded => continue,
|
||||
}
|
||||
}
|
||||
|
||||
try bw.flush();
|
||||
}
|
||||
@ -302,6 +302,7 @@ const usage_build_generic =
|
||||
\\ pe Portable Executable (Windows)
|
||||
\\ coff Common Object File Format (Windows)
|
||||
\\ macho macOS relocatables
|
||||
\\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
|
||||
\\ hex (planned) Intel IHEX
|
||||
\\ raw (planned) Dump machine code directly
|
||||
\\ -dirafter [dir] Add directory to AFTER include search path
|
||||
@ -1515,6 +1516,8 @@ fn buildOutputType(
|
||||
break :blk .hex;
|
||||
} else if (mem.eql(u8, ofmt, "raw")) {
|
||||
break :blk .raw;
|
||||
} else if (mem.eql(u8, ofmt, "spirv")) {
|
||||
break :blk .spirv;
|
||||
} else {
|
||||
fatal("unsupported object format: {s}", .{ofmt});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user