| ... | ... | @@ -93,6 +93,14 @@ pub const Global = struct { |
| 93 | 93 | end_inst: u32, |
| 94 | 94 | }; |
| 95 | 95 | |
| 96 | /// This models a kernel entry point. |
| 97 | pub const EntryPoint = struct { |
| 98 | /// The declaration that should be exported. |
| 99 | decl_index: Decl.Index, |
| 100 | /// The name of the kernel to be exported. |
| 101 | name: []const u8, |
| 102 | }; |
| 103 | |
| 96 | 104 | /// A general-purpose allocator which may be used to allocate resources for this module |
| 97 | 105 | gpa: Allocator, |
| 98 | 106 | |
| ... | ... | @@ -107,8 +115,7 @@ sections: struct { |
| 107 | 115 | extensions: Section = .{}, |
| 108 | 116 | // OpExtInstImport instructions - skip for now. |
| 109 | 117 | // memory model defined by target, not required here. |
| 110 | | /// OpEntryPoint instructions. |
| 111 | | entry_points: Section = .{}, |
| 118 | /// OpEntryPoint instructions - Handled by `self.entry_points`. |
| 112 | 119 | /// OpExecutionMode and OpExecutionModeId instructions. |
| 113 | 120 | execution_modes: Section = .{}, |
| 114 | 121 | /// OpString, OpSourcExtension, OpSource, OpSourceContinued. |
| ... | ... | @@ -143,8 +150,13 @@ type_cache: TypeCache = .{}, |
| 143 | 150 | /// Set of Decls, referred to by Decl.Index. |
| 144 | 151 | decls: std.ArrayListUnmanaged(Decl) = .{}, |
| 145 | 152 | |
| 153 | /// List of dependencies, per decl. This list holds all the dependencies, sliced by the |
| 154 | /// begin_dep and end_dep in `self.decls`. |
| 146 | 155 | decl_deps: std.ArrayListUnmanaged(Decl.Index) = .{}, |
| 147 | 156 | |
| 157 | /// The list of entry points that should be exported from this module. |
| 158 | entry_points: std.ArrayListUnmanaged(EntryPoint) = .{}, |
| 159 | |
| 148 | 160 | /// The fields in this structure help to maintain the required order for global variables. |
| 149 | 161 | globals: struct { |
| 150 | 162 | /// Set of globals, referred to by Decl.Index. |
| ... | ... | @@ -166,7 +178,6 @@ pub fn init(gpa: Allocator, arena: Allocator) Module { |
| 166 | 178 | pub fn deinit(self: *Module) void { |
| 167 | 179 | self.sections.capabilities.deinit(self.gpa); |
| 168 | 180 | self.sections.extensions.deinit(self.gpa); |
| 169 | | self.sections.entry_points.deinit(self.gpa); |
| 170 | 181 | self.sections.execution_modes.deinit(self.gpa); |
| 171 | 182 | self.sections.debug_strings.deinit(self.gpa); |
| 172 | 183 | self.sections.debug_names.deinit(self.gpa); |
| ... | ... | @@ -180,6 +191,8 @@ pub fn deinit(self: *Module) void { |
| 180 | 191 | self.decls.deinit(self.gpa); |
| 181 | 192 | self.decl_deps.deinit(self.gpa); |
| 182 | 193 | |
| 194 | self.entry_points.deinit(self.gpa); |
| 195 | |
| 183 | 196 | self.globals.globals.deinit(self.gpa); |
| 184 | 197 | self.globals.section.deinit(self.gpa); |
| 185 | 198 | |
| ... | ... | @@ -202,16 +215,16 @@ pub fn idBound(self: Module) Word { |
| 202 | 215 | |
| 203 | 216 | fn orderGlobalsInto( |
| 204 | 217 | self: *Module, |
| 205 | | index: Decl.Index, |
| 218 | decl_index: Decl.Index, |
| 206 | 219 | section: *Section, |
| 207 | 220 | seen: *std.DynamicBitSetUnmanaged, |
| 208 | 221 | ) !void { |
| 209 | | const decl = self.declPtr(index); |
| 222 | const decl = self.declPtr(decl_index); |
| 210 | 223 | const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep]; |
| 211 | | const global = self.globalPtr(index).?; |
| 224 | const global = self.globalPtr(decl_index).?; |
| 212 | 225 | const insts = self.globals.section.instructions.items[global.begin_inst..global.end_inst]; |
| 213 | 226 | |
| 214 | | seen.set(@enumToInt(index)); |
| 227 | seen.set(@enumToInt(decl_index)); |
| 215 | 228 | |
| 216 | 229 | for (deps) |dep| { |
| 217 | 230 | if (!seen.isSet(@enumToInt(dep))) { |
| ... | ... | @@ -229,6 +242,8 @@ fn orderGlobals(self: *Module) !Section { |
| 229 | 242 | defer seen.deinit(self.gpa); |
| 230 | 243 | |
| 231 | 244 | var ordered_globals = Section{}; |
| 245 | errdefer ordered_globals.deinit(self.gpa); |
| 246 | |
| 232 | 247 | for (globals) |decl_index| { |
| 233 | 248 | if (!seen.isSet(@enumToInt(decl_index))) { |
| 234 | 249 | try self.orderGlobalsInto(decl_index, &ordered_globals, &seen); |
| ... | ... | @@ -238,6 +253,56 @@ fn orderGlobals(self: *Module) !Section { |
| 238 | 253 | return ordered_globals; |
| 239 | 254 | } |
| 240 | 255 | |
| 256 | fn addEntryPointDeps( |
| 257 | self: *Module, |
| 258 | decl_index: Decl.Index, |
| 259 | seen: *std.DynamicBitSetUnmanaged, |
| 260 | interface: *std.ArrayList(IdRef), |
| 261 | ) !void { |
| 262 | const decl = self.declPtr(decl_index); |
| 263 | const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep]; |
| 264 | |
| 265 | seen.set(@enumToInt(decl_index)); |
| 266 | |
| 267 | if (self.globalPtr(decl_index)) |global| { |
| 268 | try interface.append(global.result_id); |
| 269 | } |
| 270 | |
| 271 | for (deps) |dep| { |
| 272 | if (!seen.isSet(@enumToInt(dep))) { |
| 273 | try self.addEntryPointDeps(dep, seen, interface); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | fn entryPoints(self: *Module) !Section { |
| 279 | var entry_points = Section{}; |
| 280 | errdefer entry_points.deinit(self.gpa); |
| 281 | |
| 282 | var interface = std.ArrayList(IdRef).init(self.gpa); |
| 283 | defer interface.deinit(); |
| 284 | |
| 285 | var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len); |
| 286 | defer seen.deinit(self.gpa); |
| 287 | |
| 288 | for (self.entry_points.items) |entry_point| { |
| 289 | interface.items.len = 0; |
| 290 | seen.setRangeValue(.{ .start = 0, .end = self.decls.items.len }, false); |
| 291 | |
| 292 | try self.addEntryPointDeps(entry_point.decl_index, &seen, &interface); |
| 293 | |
| 294 | const entry_point_id = self.declPtr(entry_point.decl_index).result_id; |
| 295 | try entry_points.emit(self.gpa, .OpEntryPoint, .{ |
| 296 | .execution_model = .Kernel, |
| 297 | .entry_point = entry_point_id, |
| 298 | .name = entry_point.name, |
| 299 | .interface = interface.items, |
| 300 | }); |
| 301 | } |
| 302 | |
| 303 | return entry_points; |
| 304 | } |
| 305 | |
| 241 | 306 | /// Emit this module as a spir-v binary. |
| 242 | 307 | pub fn flush(self: *Module, file: std.fs.File) !void { |
| 243 | 308 | // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction" |
| ... | ... | @@ -256,12 +321,15 @@ pub fn flush(self: *Module, file: std.fs.File) !void { |
| 256 | 321 | var globals = try self.orderGlobals(); |
| 257 | 322 | defer globals.deinit(self.gpa); |
| 258 | 323 | |
| 324 | var entry_points = try self.entryPoints(); |
| 325 | defer entry_points.deinit(self.gpa); |
| 326 | |
| 259 | 327 | // Note: needs to be kept in order according to section 2.3! |
| 260 | 328 | const buffers = &[_][]const Word{ |
| 261 | 329 | &header, |
| 262 | 330 | self.sections.capabilities.toWords(), |
| 263 | 331 | self.sections.extensions.toWords(), |
| 264 | | self.sections.entry_points.toWords(), |
| 332 | entry_points.toWords(), |
| 265 | 333 | self.sections.execution_modes.toWords(), |
| 266 | 334 | self.sections.debug_strings.toWords(), |
| 267 | 335 | self.sections.debug_names.toWords(), |
| ... | ... | @@ -795,3 +863,10 @@ pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32) void |
| 795 | 863 | global.begin_inst = begin_inst; |
| 796 | 864 | global.end_inst = @intCast(u32, self.globals.section.instructions.items.len); |
| 797 | 865 | } |
| 866 | |
| 867 | pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8) !void { |
| 868 | try self.entry_points.append(self.gpa, .{ |
| 869 | .decl_index = decl_index, |
| 870 | .name = try self.arena.dupe(u8, name), |
| 871 | }); |
| 872 | } |