mirror of
https://github.com/ziglang/zig.git
synced 2026-01-30 03:03:46 +00:00
SPIR-V: Make emitting binary more efficient
This commit is contained in:
parent
02c138fe70
commit
71ac82ecb0
@ -19,4 +19,10 @@ pub const SPIRVModule = struct {
|
|||||||
pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {
|
pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn writeInstruction(code: *std.ArrayList(u32), instr: spec.Opcode, args: []const u32) !void {
|
||||||
|
const word_count = @intCast(u32, args.len + 1);
|
||||||
|
try code.append((word_count << 16) | @enumToInt(instr));
|
||||||
|
try code.appendSlice(args);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,23 @@ const trace = @import("../tracy.zig").trace;
|
|||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const spec = @import("../codegen/spirv/spec.zig");
|
const spec = @import("../codegen/spirv/spec.zig");
|
||||||
|
|
||||||
//! SPIR-V Documentation: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html
|
//! SPIR-V Spec documentation: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html
|
||||||
|
//! According to above documentation, a SPIR-V module has the following logical layout:
|
||||||
|
//! Header.
|
||||||
|
//! OpCapability instructions.
|
||||||
|
//! OpExtension instructions.
|
||||||
|
//! OpExtInstImport instructions.
|
||||||
|
//! A single OpMemoryModel instruction.
|
||||||
|
//! All entry points, declared with OpEntryPoint instructions.
|
||||||
|
//! All execution-mode declarators; OpExecutionMode and OpExecutionModeId instructions.
|
||||||
|
//! Debug instructions:
|
||||||
|
//! - First, OpString, OpSourceExtension, OpSource, OpSourceContinued (no forward references).
|
||||||
|
//! - OpName and OpMemberName instructions.
|
||||||
|
//! - OpModuleProcessed instructions.
|
||||||
|
//! All annotation (decoration) instructions.
|
||||||
|
//! All type declaration instructions, constant instructions, global variable declarations, (preferrably) OpUndef instructions.
|
||||||
|
//! All function declarations without a body (extern functions presumably).
|
||||||
|
//! All regular functions.
|
||||||
|
|
||||||
pub const FnData = struct {
|
pub const FnData = struct {
|
||||||
id: ?u32 = null,
|
id: ?u32 = null,
|
||||||
@ -103,7 +119,6 @@ pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {
|
|||||||
decl.fn_link.spirv.code.deinit(self.base.allocator);
|
decl.fn_link.spirv.code.deinit(self.base.allocator);
|
||||||
decl.fn_link.spirv = undefined;
|
decl.fn_link.spirv = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(self: *SpirV, comp: *Compilation) !void {
|
pub fn flush(self: *SpirV, comp: *Compilation) !void {
|
||||||
if (build_options.have_llvm and self.base.options.use_lld) {
|
if (build_options.have_llvm and self.base.options.use_lld) {
|
||||||
return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
|
return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
|
||||||
@ -118,34 +133,60 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
|
|||||||
|
|
||||||
const module = self.base.options.module.?;
|
const module = self.base.options.module.?;
|
||||||
|
|
||||||
const file = self.base.file.?;
|
var binary = std.ArrayList(u32).init(self.base.allocator);
|
||||||
var bw = std.io.bufferedWriter(file.writer());
|
defer binary.deinit();
|
||||||
const writer = bw.writer();
|
|
||||||
|
|
||||||
// Header
|
// 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.
|
const header = [_]u32{
|
||||||
try writer.writeIntLittle(u32, spec.magic_number);
|
spec.magic_number,
|
||||||
try writer.writeIntLittle(u32, (spec.version.major << 16) | (spec.version.minor) << 8);
|
(spec.version.major << 16) | (spec.version.minor << 8),
|
||||||
try writer.writeIntLittle(u32, 0); // TODO: Register Zig compiler magic number.
|
0, // TODO: Register Zig compiler magic number.
|
||||||
try writer.writeIntLittle(u32, self.spirv_module.idBound());
|
self.spirv_module.idBound(),
|
||||||
try writer.writeIntLittle(u32, 0); // Schema.
|
0, // Schema (currently reserved for future use in the SPIR-V spec).
|
||||||
|
};
|
||||||
|
try binary.appendSlice(&header);
|
||||||
|
}
|
||||||
|
|
||||||
// Declarations
|
// Collect list of buffers to write.
|
||||||
|
// SPIR-V files support both little and big endian words. The actual format is
|
||||||
|
// disambiguated by the magic number, and so theoretically we don't need to worry
|
||||||
|
// about endian-ness when writing the final binary.
|
||||||
|
var all_buffers = std.ArrayList(std.os.iovec_const).init(self.base.allocator);
|
||||||
|
defer all_buffers.deinit();
|
||||||
|
|
||||||
|
// Pre-allocate enough for the binary info + all functions
|
||||||
|
try all_buffers.ensureCapacity(module.decl_table.count() + 1);
|
||||||
|
|
||||||
|
all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items));
|
||||||
|
|
||||||
|
// Functions
|
||||||
for (module.decl_table.items()) |entry| {
|
for (module.decl_table.items()) |entry| {
|
||||||
const decl = entry.value;
|
const decl = entry.value;
|
||||||
switch (decl.typed_value) {
|
switch (decl.typed_value) {
|
||||||
.most_recent => |tvm| {
|
.most_recent => |tvm| {
|
||||||
const fn_data = &decl.fn_link.spirv;
|
const fn_data = &decl.fn_link.spirv;
|
||||||
|
all_buffers.appendAssumeCapacity(wordsToIovConst(fn_data.code.items));
|
||||||
// TODO: This could probably be more efficient.
|
|
||||||
for (fn_data.code.items) |word| {
|
|
||||||
try writer.writeIntLittle(u32, word);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.never_succeeded => continue,
|
.never_succeeded => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try bw.flush();
|
var file_size: u64 = 0;
|
||||||
|
for (all_buffers.items) |iov| {
|
||||||
|
file_size += iov.iov_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = self.base.file.?;
|
||||||
|
try file.seekTo(0);
|
||||||
|
try file.setEndPos(file_size);
|
||||||
|
try file.pwritevAll(all_buffers.items, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wordsToIovConst(words: []const u32) std.os.iovec_const {
|
||||||
|
const bytes = std.mem.sliceAsBytes(words);
|
||||||
|
return .{
|
||||||
|
.iov_base = bytes.ptr,
|
||||||
|
.iov_len = bytes.len,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user