Commit 801732aebd
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);
- }
};
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 .{