| ... | @@ -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(); |
| 133 | | 133 | |
| 134 | const module = self.base.options.module.?; | 134 | const module = self.base.options.module.?; |
| | 135 | const target = comp.getTarget(); |
| 135 | | 136 | |
| 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(); |
| 138 | | 139 | |
| 139 | // Header | 140 | // 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); |
| 150 | | 153 | |
| 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 is | 155 | // 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 { |
| 160 | | 163 | |
| 161 | all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items)); | 164 | all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items)); |
| 162 | | 165 | |
| 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 | } |
| 185 | | 187 | |
| | 188 | fn 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 | |
| | 200 | fn 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 | |
| 186 | fn wordsToIovConst(words: []const u32) std.os.iovec_const { | 223 | fn 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 .{ |