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");...@@ -3,6 +3,12 @@ const spec = @import("spirv/spec.zig");
3const Module = @import("../Module.zig");3const Module = @import("../Module.zig");
4const Decl = Module.Decl;4const 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
6pub const SPIRVModule = struct {12pub const SPIRVModule = struct {
7 // TODO: Also use a free list.13 // TODO: Also use a free list.
8 next_id: u32 = 0,14 next_id: u32 = 0,
...@@ -19,10 +25,4 @@ pub const SPIRVModule = struct {...@@ -19,10 +25,4 @@ pub const SPIRVModule = struct {
19 pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {25 pub fn genDecl(self: SPIRVModule, id: u32, code: *std.ArrayList(u32), decl: *Decl) !void {
2026
21 }27 }
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 }
28};28};
src/link/SpirV.zig+49-12
...@@ -132,21 +132,24 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {...@@ -132,21 +132,24 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
132 defer tracy.end();132 defer tracy.end();
133133
134 const module = self.base.options.module.?;134 const module = self.base.options.module.?;
135 const target = comp.getTarget();
135136
136 var binary = std.ArrayList(u32).init(self.base.allocator);137 var binary = std.ArrayList(u32).init(self.base.allocator);
137 defer binary.deinit();138 defer binary.deinit();
138139
139 // Header140 // Note: The order of adding functions to the final binary
140 {141 // follows the SPIR-V logical moduel format!
141 const header = [_]u32{142
142 spec.magic_number,143 try binary.appendSlice(&[_]u32{
143 (spec.version.major << 16) | (spec.version.minor << 8),144 spec.magic_number,
144 0, // TODO: Register Zig compiler magic number.145 (spec.version.major << 16) | (spec.version.minor << 8),
145 self.spirv_module.idBound(),146 0, // TODO: Register Zig compiler magic number.
146 0, // Schema (currently reserved for future use in the SPIR-V spec).147 self.spirv_module.idBound(),
147 };148 0, // Schema (currently reserved for future use in the SPIR-V spec).
148 try binary.appendSlice(&header);149 });
149 }150
151 try writeCapabilities(&binary, target);
152 try writeMemoryModel(&binary, target);
150153
151 // Collect list of buffers to write.154 // Collect list of buffers to write.
152 // SPIR-V files support both little and big endian words. The actual format is155 // 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 {...@@ -160,7 +163,6 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
160163
161 all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items));164 all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items));
162165
163 // Functions
164 for (module.decl_table.items()) |entry| {166 for (module.decl_table.items()) |entry| {
165 const decl = entry.value;167 const decl = entry.value;
166 switch (decl.typed_value) {168 switch (decl.typed_value) {
...@@ -183,6 +185,41 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {...@@ -183,6 +185,41 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
183 try file.pwritevAll(all_buffers.items, 0);185 try file.pwritevAll(all_buffers.items, 0);
184}186}
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
186fn wordsToIovConst(words: []const u32) std.os.iovec_const {223fn wordsToIovConst(words: []const u32) std.os.iovec_const {
187 const bytes = std.mem.sliceAsBytes(words);224 const bytes = std.mem.sliceAsBytes(words);
188 return .{225 return .{