From 801732aebd3092c539b754170032455139c7418c Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 19 Jan 2021 01:54:01 +0100 Subject: [PATCH] SPIR-V: OpMemoryModel and basic capability generation --- src/codegen/spirv.zig | 12 ++++----- src/link/SpirV.zig | 61 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 7e41913625..2fe759dc03 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -3,6 +3,12 @@ const spec = @import("spirv/spec.zig"); const Module = @import("../Module.zig"); const Decl = Module.Decl; +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); +} + pub const SPIRVModule = struct { // TODO: Also use a free list. next_id: u32 = 0, @@ -19,10 +25,4 @@ pub const SPIRVModule = struct { 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); - } }; diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 03acf3c31e..80469726e0 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -132,21 +132,24 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { defer tracy.end(); const module = self.base.options.module.?; + const target = comp.getTarget(); var binary = std.ArrayList(u32).init(self.base.allocator); defer binary.deinit(); - // Header - { - const header = [_]u32{ - spec.magic_number, - (spec.version.major << 16) | (spec.version.minor << 8), - 0, // TODO: Register Zig compiler magic number. - self.spirv_module.idBound(), - 0, // Schema (currently reserved for future use in the SPIR-V spec). - }; - try binary.appendSlice(&header); - } + // Note: The order of adding functions to the final binary + // follows the SPIR-V logical moduel format! + + try binary.appendSlice(&[_]u32{ + spec.magic_number, + (spec.version.major << 16) | (spec.version.minor << 8), + 0, // TODO: Register Zig compiler magic number. + self.spirv_module.idBound(), + 0, // Schema (currently reserved for future use in the SPIR-V spec). + }); + + try writeCapabilities(&binary, target); + try writeMemoryModel(&binary, target); // Collect list of buffers to write. // SPIR-V files support both little and big endian words. The actual format is @@ -160,7 +163,6 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items)); - // Functions for (module.decl_table.items()) |entry| { const decl = entry.value; switch (decl.typed_value) { @@ -183,6 +185,41 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { try file.pwritevAll(all_buffers.items, 0); } +fn writeCapabilities(binary: *std.ArrayList(u32), target: std.Target) !void { + // TODO: Integrate with a hypothetical feature system + const cap: spec.Capability = switch (target.os.tag) { + .opencl => .Kernel, + .glsl450 => .Shader, + .vulkan => .VulkanMemoryModel, + else => unreachable, // TODO + }; + + try codegen.writeInstruction(binary, .OpCapability, &[_]u32{ @enumToInt(cap) }); +} + +fn writeMemoryModel(binary: *std.ArrayList(u32), target: std.Target) !void { + const addressing_model = switch (target.os.tag) { + .opencl => switch (target.cpu.arch) { + .spirv32 => spec.AddressingModel.Physical32, + .spirv64 => spec.AddressingModel.Physical64, + else => unreachable, // TODO + }, + .glsl450, .vulkan => spec.AddressingModel.Logical, + else => unreachable, // TODO + }; + + const memory_model: spec.MemoryModel = switch (target.os.tag) { + .opencl => .OpenCL, + .glsl450 => .GLSL450, + .vulkan => .Vulkan, + else => unreachable, + }; + + try codegen.writeInstruction(binary, .OpMemoryModel, &[_]u32{ + @enumToInt(addressing_model), @enumToInt(memory_model) + }); +} + fn wordsToIovConst(words: []const u32) std.os.iovec_const { const bytes = std.mem.sliceAsBytes(words); return .{