authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-01-19 01:54:01+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-01-19 15:28:17+01:00
log801732aebd3092c539b754170032455139c7418c
tree02d46e2d85d3e98e511055510fec79e4f38d7b37
parent71ac82ecb028605545b67eaa50b34f4e2494de44

SPIR-V: OpMemoryModel and basic capability generation


2 files changed, 55 insertions(+), 18 deletions(-)

src/codegen/spirv.zig+6-6
......@@ -3,6 +3,12 @@ const spec = @import("spirv/spec.zig");
33const Module = @import("../Module.zig");
44const Decl = Module.Decl;
55
6pub fn writeInstruction(code: *std.ArrayList(u32), instr: spec.Opcode, args: []const u32) !void {
7 const word_count = @intCast(u32, args.len + 1);
8 try code.append((word_count << 16) | @enumToInt(instr));
9 try code.appendSlice(args);
10}
11
612pub const SPIRVModule = struct {
713 // TODO: Also use a free list.
814 next_id: u32 = 0,
......@@ -19,10 +25,4 @@ pub const SPIRVModule = struct {
1925 pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {
2026
2127 }
22
23 pub fn writeInstruction(code: *std.ArrayList(u32), instr: spec.Opcode, args: []const u32) !void {
24 const word_count = @intCast(u32, args.len + 1);
25 try code.append((word_count << 16) | @enumToInt(instr));
26 try code.appendSlice(args);
27 }
2828};
src/link/SpirV.zig+49-12
......@@ -132,21 +132,24 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
132132 defer tracy.end();
133133
134134 const module = self.base.options.module.?;
135 const target = comp.getTarget();
135136
136137 var binary = std.ArrayList(u32).init(self.base.allocator);
137138 defer binary.deinit();
138139
139 // Header
140 {
141 const header = [_]u32{
142 spec.magic_number,
143 (spec.version.major << 16) | (spec.version.minor << 8),
144 0, // TODO: Register Zig compiler magic number.
145 self.spirv_module.idBound(),
146 0, // Schema (currently reserved for future use in the SPIR-V spec).
147 };
148 try binary.appendSlice(&header);
149 }
140 // Note: The order of adding functions to the final binary
141 // follows the SPIR-V logical moduel format!
142
143 try binary.appendSlice(&[_]u32{
144 spec.magic_number,
145 (spec.version.major << 16) | (spec.version.minor << 8),
146 0, // TODO: Register Zig compiler magic number.
147 self.spirv_module.idBound(),
148 0, // Schema (currently reserved for future use in the SPIR-V spec).
149 });
150
151 try writeCapabilities(&binary, target);
152 try writeMemoryModel(&binary, target);
150153
151154 // Collect list of buffers to write.
152155 // 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 {
160163
161164 all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items));
162165
163 // Functions
164166 for (module.decl_table.items()) |entry| {
165167 const decl = entry.value;
166168 switch (decl.typed_value) {
......@@ -183,6 +185,41 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
183185 try file.pwritevAll(all_buffers.items, 0);
184186}
185187
188fn writeCapabilities(binary: *std.ArrayList(u32), target: std.Target) !void {
189 // TODO: Integrate with a hypothetical feature system
190 const cap: spec.Capability = switch (target.os.tag) {
191 .opencl => .Kernel,
192 .glsl450 => .Shader,
193 .vulkan => .VulkanMemoryModel,
194 else => unreachable, // TODO
195 };
196
197 try codegen.writeInstruction(binary, .OpCapability, &[_]u32{ @enumToInt(cap) });
198}
199
200fn writeMemoryModel(binary: *std.ArrayList(u32), target: std.Target) !void {
201 const addressing_model = switch (target.os.tag) {
202 .opencl => switch (target.cpu.arch) {
203 .spirv32 => spec.AddressingModel.Physical32,
204 .spirv64 => spec.AddressingModel.Physical64,
205 else => unreachable, // TODO
206 },
207 .glsl450, .vulkan => spec.AddressingModel.Logical,
208 else => unreachable, // TODO
209 };
210
211 const memory_model: spec.MemoryModel = switch (target.os.tag) {
212 .opencl => .OpenCL,
213 .glsl450 => .GLSL450,
214 .vulkan => .Vulkan,
215 else => unreachable,
216 };
217
218 try codegen.writeInstruction(binary, .OpMemoryModel, &[_]u32{
219 @enumToInt(addressing_model), @enumToInt(memory_model)
220 });
221}
222
186223fn wordsToIovConst(words: []const u32) std.os.iovec_const {
187224 const bytes = std.mem.sliceAsBytes(words);
188225 return .{