| ... | ... | @@ -132,21 +132,24 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { |
| 132 | 132 | defer tracy.end(); |
| 133 | 133 | |
| 134 | 134 | const module = self.base.options.module.?; |
| 135 | const target = comp.getTarget(); |
| 135 | 136 | |
| 136 | 137 | var binary = std.ArrayList(u32).init(self.base.allocator); |
| 137 | 138 | defer binary.deinit(); |
| 138 | 139 | |
| 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); |
| 150 | 153 | |
| 151 | 154 | // Collect list of buffers to write. |
| 152 | 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 | 163 | |
| 161 | 164 | all_buffers.appendAssumeCapacity(wordsToIovConst(binary.items)); |
| 162 | 165 | |
| 163 | | // Functions |
| 164 | 166 | for (module.decl_table.items()) |entry| { |
| 165 | 167 | const decl = entry.value; |
| 166 | 168 | switch (decl.typed_value) { |
| ... | ... | @@ -183,6 +185,41 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void { |
| 183 | 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 | 223 | fn wordsToIovConst(words: []const u32) std.os.iovec_const { |
| 187 | 224 | const bytes = std.mem.sliceAsBytes(words); |
| 188 | 225 | return .{ |