| ... | @@ -53,20 +53,141 @@ const Block = struct { | ... | @@ -53,20 +53,141 @@ const Block = struct { |
| 53 | const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, *Block); | 53 | const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, *Block); |
| 54 | | 54 | |
| 55 | /// Maps Zig decl indices to SPIR-V linking information. | 55 | /// Maps Zig decl indices to SPIR-V linking information. |
| 56 | pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, SpvModule.Decl.Index); | 56 | pub const DeclLinkMap = std.AutoHashMapUnmanaged(Decl.Index, SpvModule.Decl.Index); |
| 57 | | 57 | |
| 58 | /// Maps anon decl indices to SPIR-V linking information. | 58 | /// Maps anon decl indices to SPIR-V linking information. |
| 59 | pub const AnonDeclLinkMap = std.AutoHashMap(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index); | 59 | pub const AnonDeclLinkMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index); |
| | 60 | |
| | 61 | /// This structure holds information that is relevant to the entire compilation, |
| | 62 | /// in contrast to `DeclGen`, which only holds relevant information about a |
| | 63 | /// single decl. |
| | 64 | pub const Object = struct { |
| | 65 | /// A general-purpose allocator that can be used for any allocation for this Object. |
| | 66 | gpa: Allocator, |
| | 67 | |
| | 68 | /// the SPIR-V module that represents the final binary. |
| | 69 | spv: SpvModule, |
| | 70 | |
| | 71 | /// The Zig module that this object file is generated for. |
| | 72 | /// A map of Zig decl indices to SPIR-V decl indices. |
| | 73 | decl_link: DeclLinkMap = .{}, |
| | 74 | |
| | 75 | /// A map of Zig InternPool indices for anonymous decls to SPIR-V decl indices. |
| | 76 | anon_decl_link: AnonDeclLinkMap = .{}, |
| | 77 | |
| | 78 | /// A map that maps AIR intern pool indices to SPIR-V cache references (which |
| | 79 | /// is basically the same thing except for SPIR-V). |
| | 80 | /// This map is typically only used for structures that are deemed heavy enough |
| | 81 | /// that it is worth to store them here. The SPIR-V module also interns types, |
| | 82 | /// and so the main purpose of this map is to avoid recomputation and to |
| | 83 | /// cache extra information about the type rather than to aid in validity |
| | 84 | /// of the SPIR-V module. |
| | 85 | type_map: TypeMap = .{}, |
| | 86 | |
| | 87 | pub fn init(gpa: Allocator) Object { |
| | 88 | return .{ |
| | 89 | .gpa = gpa, |
| | 90 | .spv = SpvModule.init(gpa), |
| | 91 | }; |
| | 92 | } |
| | 93 | |
| | 94 | pub fn deinit(self: *Object) void { |
| | 95 | self.spv.deinit(); |
| | 96 | self.decl_link.deinit(self.gpa); |
| | 97 | self.anon_decl_link.deinit(self.gpa); |
| | 98 | self.type_map.deinit(self.gpa); |
| | 99 | } |
| | 100 | |
| | 101 | fn genDecl( |
| | 102 | self: *Object, |
| | 103 | mod: *Module, |
| | 104 | decl_index: Decl.Index, |
| | 105 | air: Air, |
| | 106 | liveness: Liveness, |
| | 107 | ) !void { |
| | 108 | var decl_gen = DeclGen{ |
| | 109 | .gpa = self.gpa, |
| | 110 | .object = self, |
| | 111 | .module = mod, |
| | 112 | .spv = &self.spv, |
| | 113 | .decl_index = decl_index, |
| | 114 | .air = air, |
| | 115 | .liveness = liveness, |
| | 116 | .type_map = &self.type_map, |
| | 117 | .current_block_label_id = undefined, |
| | 118 | }; |
| | 119 | defer decl_gen.deinit(); |
| | 120 | |
| | 121 | decl_gen.genDecl() catch |err| switch (err) { |
| | 122 | error.CodegenFail => { |
| | 123 | try mod.failed_decls.put(mod.gpa, decl_index, decl_gen.error_msg.?); |
| | 124 | }, |
| | 125 | else => |other| { |
| | 126 | // There might be an error that happened *after* self.error_msg |
| | 127 | // was already allocated, so be sure to free it. |
| | 128 | if (decl_gen.error_msg) |error_msg| { |
| | 129 | error_msg.deinit(mod.gpa); |
| | 130 | } |
| | 131 | |
| | 132 | return other; |
| | 133 | }, |
| | 134 | }; |
| | 135 | } |
| | 136 | |
| | 137 | pub fn updateFunc( |
| | 138 | self: *Object, |
| | 139 | mod: *Module, |
| | 140 | func_index: InternPool.Index, |
| | 141 | air: Air, |
| | 142 | liveness: Liveness, |
| | 143 | ) !void { |
| | 144 | const decl_index = mod.funcInfo(func_index).owner_decl; |
| | 145 | // TODO: Separate types for generating decls and functions? |
| | 146 | try self.genDecl(mod, decl_index, air, liveness); |
| | 147 | } |
| | 148 | |
| | 149 | pub fn updateDecl( |
| | 150 | self: *Object, |
| | 151 | mod: *Module, |
| | 152 | decl_index: Decl.Index, |
| | 153 | ) !void { |
| | 154 | try self.genDecl(mod, decl_index, undefined, undefined); |
| | 155 | } |
| | 156 | |
| | 157 | /// Fetch or allocate a result id for decl index. This function also marks the decl as alive. |
| | 158 | /// Note: Function does not actually generate the decl, it just allocates an index. |
| | 159 | pub fn resolveDecl(self: *Object, mod: *Module, decl_index: Decl.Index) !SpvModule.Decl.Index { |
| | 160 | const decl = mod.declPtr(decl_index); |
| | 161 | try mod.markDeclAlive(decl); |
| | 162 | |
| | 163 | const entry = try self.decl_link.getOrPut(self.gpa, decl_index); |
| | 164 | if (!entry.found_existing) { |
| | 165 | // TODO: Extern fn? |
| | 166 | const kind: SpvModule.DeclKind = if (decl.val.isFuncBody(mod)) |
| | 167 | .func |
| | 168 | else |
| | 169 | .global; |
| | 170 | |
| | 171 | entry.value_ptr.* = try self.spv.allocDecl(kind); |
| | 172 | } |
| | 173 | |
| | 174 | return entry.value_ptr.*; |
| | 175 | } |
| | 176 | }; |
| 60 | | 177 | |
| 61 | /// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that. | 178 | /// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that. |
| 62 | pub const DeclGen = struct { | 179 | const DeclGen = struct { |
| 63 | /// A general-purpose allocator that can be used for any allocations for this DeclGen. | 180 | /// A general-purpose allocator that can be used for any allocations for this DeclGen. |
| 64 | gpa: Allocator, | 181 | gpa: Allocator, |
| 65 | | 182 | |
| | 183 | /// The object that this decl is generated into. |
| | 184 | object: *Object, |
| | 185 | |
| 66 | /// The Zig module that we are generating decls for. | 186 | /// The Zig module that we are generating decls for. |
| 67 | module: *Module, | 187 | module: *Module, |
| 68 | | 188 | |
| 69 | /// The SPIR-V module that instructions should be emitted into. | 189 | /// The SPIR-V module that instructions should be emitted into. |
| | 190 | /// This is the same as `self.object.spv`, repeated here for brevity. |
| 70 | spv: *SpvModule, | 191 | spv: *SpvModule, |
| 71 | | 192 | |
| 72 | /// The decl we are currently generating code for. | 193 | /// The decl we are currently generating code for. |
| ... | @@ -80,30 +201,19 @@ pub const DeclGen = struct { | ... | @@ -80,30 +201,19 @@ pub const DeclGen = struct { |
| 80 | /// Note: If the declaration is not a function, this value will be undefined! | 201 | /// Note: If the declaration is not a function, this value will be undefined! |
| 81 | liveness: Liveness, | 202 | liveness: Liveness, |
| 82 | | 203 | |
| 83 | /// Maps Zig Decl indices to SPIR-V decl indices. | | |
| 84 | decl_link: *DeclLinkMap, | | |
| 85 | | | |
| 86 | /// Maps Zig anon decl indices to SPIR-V decl indices. | | |
| 87 | anon_decl_link: *AnonDeclLinkMap, | | |
| 88 | | | |
| 89 | /// An array of function argument result-ids. Each index corresponds with the | 204 | /// An array of function argument result-ids. Each index corresponds with the |
| 90 | /// function argument of the same index. | 205 | /// function argument of the same index. |
| 91 | args: std.ArrayListUnmanaged(IdRef) = .{}, | 206 | args: std.ArrayListUnmanaged(IdRef) = .{}, |
| 92 | | 207 | |
| 93 | /// A counter to keep track of how many `arg` instructions we've seen yet. | 208 | /// A counter to keep track of how many `arg` instructions we've seen yet. |
| 94 | next_arg_index: u32, | 209 | next_arg_index: u32 = 0, |
| 95 | | 210 | |
| 96 | /// A map keeping track of which instruction generated which result-id. | 211 | /// A map keeping track of which instruction generated which result-id. |
| 97 | inst_results: InstMap = .{}, | 212 | inst_results: InstMap = .{}, |
| 98 | | 213 | |
| 99 | /// A map that maps AIR intern pool indices to SPIR-V cache references (which | 214 | /// A map that maps AIR intern pool indices to SPIR-V cache references. |
| 100 | /// is basically the same thing except for SPIR-V). | 215 | /// See Object.type_map |
| 101 | /// This map is typically only used for structures that are deemed heavy enough | 216 | type_map: *TypeMap, |
| 102 | /// that it is worth to store them here. The SPIR-V module also interns types, | | |
| 103 | /// and so the main purpose of this map is to avoid recomputation and to | | |
| 104 | /// cache extra information about the type rather than to aid in validity | | |
| 105 | /// of the SPIR-V module. | | |
| 106 | type_map: TypeMap = .{}, | | |
| 107 | | 217 | |
| 108 | /// We need to keep track of result ids for block labels, as well as the 'incoming' | 218 | /// We need to keep track of result ids for block labels, as well as the 'incoming' |
| 109 | /// blocks for a block. | 219 | /// blocks for a block. |
| ... | @@ -121,7 +231,7 @@ pub const DeclGen = struct { | ... | @@ -121,7 +231,7 @@ pub const DeclGen = struct { |
| 121 | | 231 | |
| 122 | /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message. | 232 | /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message. |
| 123 | /// Memory is owned by `module.gpa`. | 233 | /// Memory is owned by `module.gpa`. |
| 124 | error_msg: ?*Module.ErrorMsg, | 234 | error_msg: ?*Module.ErrorMsg = null, |
| 125 | | 235 | |
| 126 | /// Possible errors the `genDecl` function may return. | 236 | /// Possible errors the `genDecl` function may return. |
| 127 | const Error = error{ CodegenFail, OutOfMemory }; | 237 | const Error = error{ CodegenFail, OutOfMemory }; |
| ... | @@ -181,67 +291,10 @@ pub const DeclGen = struct { | ... | @@ -181,67 +291,10 @@ pub const DeclGen = struct { |
| 181 | indirect, | 291 | indirect, |
| 182 | }; | 292 | }; |
| 183 | | 293 | |
| 184 | /// Initialize the common resources of a DeclGen. Some fields are left uninitialized, | | |
| 185 | /// only set when `gen` is called. | | |
| 186 | pub fn init( | | |
| 187 | allocator: Allocator, | | |
| 188 | module: *Module, | | |
| 189 | spv: *SpvModule, | | |
| 190 | decl_link: *DeclLinkMap, | | |
| 191 | anon_decl_link: *AnonDeclLinkMap, | | |
| 192 | ) DeclGen { | | |
| 193 | return .{ | | |
| 194 | .gpa = allocator, | | |
| 195 | .module = module, | | |
| 196 | .spv = spv, | | |
| 197 | .decl_index = undefined, | | |
| 198 | .air = undefined, | | |
| 199 | .liveness = undefined, | | |
| 200 | .decl_link = decl_link, | | |
| 201 | .anon_decl_link = anon_decl_link, | | |
| 202 | .next_arg_index = undefined, | | |
| 203 | .current_block_label_id = undefined, | | |
| 204 | .error_msg = undefined, | | |
| 205 | }; | | |
| 206 | } | | |
| 207 | | | |
| 208 | /// Generate the code for `decl`. If a reportable error occurred during code generation, | | |
| 209 | /// a message is returned by this function. Callee owns the memory. If this function | | |
| 210 | /// returns such a reportable error, it is valid to be called again for a different decl. | | |
| 211 | pub fn gen(self: *DeclGen, decl_index: Decl.Index, air: Air, liveness: Liveness) !?*Module.ErrorMsg { | | |
| 212 | // Reset internal resources, we don't want to re-allocate these. | | |
| 213 | self.decl_index = decl_index; | | |
| 214 | self.air = air; | | |
| 215 | self.liveness = liveness; | | |
| 216 | self.args.items.len = 0; | | |
| 217 | self.next_arg_index = 0; | | |
| 218 | self.inst_results.clearRetainingCapacity(); | | |
| 219 | self.blocks.clearRetainingCapacity(); | | |
| 220 | self.current_block_label_id = undefined; | | |
| 221 | self.func.reset(); | | |
| 222 | self.base_line_stack.items.len = 0; | | |
| 223 | self.error_msg = null; | | |
| 224 | | | |
| 225 | self.genDecl() catch |err| switch (err) { | | |
| 226 | error.CodegenFail => return self.error_msg, | | |
| 227 | else => |others| { | | |
| 228 | // There might be an error that happened *after* self.error_msg | | |
| 229 | // was already allocated, so be sure to free it. | | |
| 230 | if (self.error_msg) |error_msg| { | | |
| 231 | error_msg.deinit(self.module.gpa); | | |
| 232 | } | | |
| 233 | return others; | | |
| 234 | }, | | |
| 235 | }; | | |
| 236 | | | |
| 237 | return null; | | |
| 238 | } | | |
| 239 | | | |
| 240 | /// Free resources owned by the DeclGen. | 294 | /// Free resources owned by the DeclGen. |
| 241 | pub fn deinit(self: *DeclGen) void { | 295 | pub fn deinit(self: *DeclGen) void { |
| 242 | self.args.deinit(self.gpa); | 296 | self.args.deinit(self.gpa); |
| 243 | self.inst_results.deinit(self.gpa); | 297 | self.inst_results.deinit(self.gpa); |
| 244 | self.type_map.deinit(self.gpa); | | |
| 245 | self.blocks.deinit(self.gpa); | 298 | self.blocks.deinit(self.gpa); |
| 246 | self.func.deinit(self.gpa); | 299 | self.func.deinit(self.gpa); |
| 247 | self.base_line_stack.deinit(self.gpa); | 300 | self.base_line_stack.deinit(self.gpa); |
| ... | @@ -277,7 +330,7 @@ pub const DeclGen = struct { | ... | @@ -277,7 +330,7 @@ pub const DeclGen = struct { |
| 277 | .func => |func| func.owner_decl, | 330 | .func => |func| func.owner_decl, |
| 278 | else => unreachable, | 331 | else => unreachable, |
| 279 | }; | 332 | }; |
| 280 | const spv_decl_index = try self.resolveDecl(fn_decl_index); | 333 | const spv_decl_index = try self.object.resolveDecl(mod, fn_decl_index); |
| 281 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 334 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| 282 | return self.spv.declPtr(spv_decl_index).result_id; | 335 | return self.spv.declPtr(spv_decl_index).result_id; |
| 283 | } | 336 | } |
| ... | @@ -288,31 +341,10 @@ pub const DeclGen = struct { | ... | @@ -288,31 +341,10 @@ pub const DeclGen = struct { |
| 288 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. | 341 | return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage. |
| 289 | } | 342 | } |
| 290 | | 343 | |
| 291 | /// Fetch or allocate a result id for decl index. This function also marks the decl as alive. | | |
| 292 | /// Note: Function does not actually generate the decl. | | |
| 293 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !SpvModule.Decl.Index { | | |
| 294 | const mod = self.module; | | |
| 295 | const decl = mod.declPtr(decl_index); | | |
| 296 | try mod.markDeclAlive(decl); | | |
| 297 | | | |
| 298 | const entry = try self.decl_link.getOrPut(decl_index); | | |
| 299 | if (!entry.found_existing) { | | |
| 300 | // TODO: Extern fn? | | |
| 301 | const kind: SpvModule.DeclKind = if (decl.val.isFuncBody(mod)) | | |
| 302 | .func | | |
| 303 | else | | |
| 304 | .global; | | |
| 305 | | | |
| 306 | entry.value_ptr.* = try self.spv.allocDecl(kind); | | |
| 307 | } | | |
| 308 | | | |
| 309 | return entry.value_ptr.*; | | |
| 310 | } | | |
| 311 | | | |
| 312 | fn resolveAnonDecl(self: *DeclGen, val: InternPool.Index, storage_class: StorageClass) !IdRef { | 344 | fn resolveAnonDecl(self: *DeclGen, val: InternPool.Index, storage_class: StorageClass) !IdRef { |
| 313 | // TODO: This cannot be a function at this point, but it should probably be handled anyway. | 345 | // TODO: This cannot be a function at this point, but it should probably be handled anyway. |
| 314 | const spv_decl_index = blk: { | 346 | const spv_decl_index = blk: { |
| 315 | const entry = try self.anon_decl_link.getOrPut(.{ val, storage_class }); | 347 | const entry = try self.object.anon_decl_link.getOrPut(self.object.gpa, .{ val, storage_class }); |
| 316 | if (entry.found_existing) { | 348 | if (entry.found_existing) { |
| 317 | try self.func.decl_deps.put(self.spv.gpa, entry.value_ptr.*, {}); | 349 | try self.func.decl_deps.put(self.spv.gpa, entry.value_ptr.*, {}); |
| 318 | return self.spv.declPtr(entry.value_ptr.*).result_id; | 350 | return self.spv.declPtr(entry.value_ptr.*).result_id; |
| ... | @@ -988,7 +1020,7 @@ pub const DeclGen = struct { | ... | @@ -988,7 +1020,7 @@ pub const DeclGen = struct { |
| 988 | return self.spv.constUndef(ty_ref); | 1020 | return self.spv.constUndef(ty_ref); |
| 989 | } | 1021 | } |
| 990 | | 1022 | |
| 991 | const spv_decl_index = try self.resolveDecl(decl_index); | 1023 | const spv_decl_index = try self.object.resolveDecl(mod, decl_index); |
| 992 | | 1024 | |
| 993 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 1025 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 994 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 1026 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| ... | @@ -1624,7 +1656,7 @@ pub const DeclGen = struct { | ... | @@ -1624,7 +1656,7 @@ pub const DeclGen = struct { |
| 1624 | const mod = self.module; | 1656 | const mod = self.module; |
| 1625 | const ip = &mod.intern_pool; | 1657 | const ip = &mod.intern_pool; |
| 1626 | const decl = mod.declPtr(self.decl_index); | 1658 | const decl = mod.declPtr(self.decl_index); |
| 1627 | const spv_decl_index = try self.resolveDecl(self.decl_index); | 1659 | const spv_decl_index = try self.object.resolveDecl(mod, self.decl_index); |
| 1628 | | 1660 | |
| 1629 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 1661 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1630 | | 1662 | |