| author | |
| committer | |
| log | 080022f6c670b0f74c39fe01096ebdbaafeda1b2 |
| tree | aa3dae7fa7f88f84a8cc32496d0db00222b16ea4 |
| parent | a3da584248c1152c01a1a7f878c164fb19b8e04a |
8 files changed, 525 insertions(+), 264 deletions(-)
lib/std/array_list.zig+1-8| ... | ... | @@ -269,13 +269,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 269 | 269 | |
| 270 | 270 | /// Bring-your-own allocator with every function call. |
| 271 | 271 | /// Initialize directly and deinitialize with `deinit` or use `toOwnedSlice`. |
| 272 | pub fn init() Self { | |
| 273 | return .{ | |
| 274 | .items = &[_]T{}, | |
| 275 | .capacity = 0, | |
| 276 | }; | |
| 277 | } | |
| 278 | ||
| 279 | 272 | pub fn ArrayListUnmanaged(comptime T: type) type { |
| 280 | 273 | return ArrayListAlignedUnmanaged(T, null); |
| 281 | 274 | } |
| ... | ... | @@ -317,7 +310,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 317 | 310 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 318 | 311 | pub fn toOwnedSlice(self: *Self, allocator: *Allocator) Slice { |
| 319 | 312 | const result = allocator.shrink(self.allocatedSlice(), self.items.len); |
| 320 | self.* = init(allocator); | |
| 313 | self.* = Self{}; | |
| 321 | 314 | return result; |
| 322 | 315 | } |
| 323 | 316 |
lib/std/mem.zig+19-9| ... | ... | @@ -279,6 +279,21 @@ pub const Allocator = struct { |
| 279 | 279 | const shrink_result = self.shrinkFn(self, non_const_ptr[0..bytes_len], Slice.alignment, 0, 1); |
| 280 | 280 | assert(shrink_result.len == 0); |
| 281 | 281 | } |
| 282 | ||
| 283 | /// Copies `m` to newly allocated memory. Caller owns the memory. | |
| 284 | pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { | |
| 285 | const new_buf = try allocator.alloc(T, m.len); | |
| 286 | copy(T, new_buf, m); | |
| 287 | return new_buf; | |
| 288 | } | |
| 289 | ||
| 290 | /// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory. | |
| 291 | pub fn dupeZ(allocator: *Allocator, comptime T: type, m: []const T) ![:0]T { | |
| 292 | const new_buf = try allocator.alloc(T, m.len + 1); | |
| 293 | copy(T, new_buf, m); | |
| 294 | new_buf[m.len] = 0; | |
| 295 | return new_buf[0..m.len :0]; | |
| 296 | } | |
| 282 | 297 | }; |
| 283 | 298 | |
| 284 | 299 | /// Copy all of source into dest at position 0. |
| ... | ... | @@ -762,19 +777,14 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { |
| 762 | 777 | return true; |
| 763 | 778 | } |
| 764 | 779 | |
| 765 | /// Copies `m` to newly allocated memory. Caller owns the memory. | |
| 780 | /// Deprecated, use `Allocator.dupe`. | |
| 766 | 781 | pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { |
| 767 | const new_buf = try allocator.alloc(T, m.len); | |
| 768 | copy(T, new_buf, m); | |
| 769 | return new_buf; | |
| 782 | return allocator.dupe(T, m); | |
| 770 | 783 | } |
| 771 | 784 | |
| 772 | /// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory. | |
| 785 | /// Deprecated, use `Allocator.dupeZ`. | |
| 773 | 786 | pub fn dupeZ(allocator: *Allocator, comptime T: type, m: []const T) ![:0]T { |
| 774 | const new_buf = try allocator.alloc(T, m.len + 1); | |
| 775 | copy(T, new_buf, m); | |
| 776 | new_buf[m.len] = 0; | |
| 777 | return new_buf[0..m.len :0]; | |
| 787 | return allocator.dupeZ(T, m); | |
| 778 | 788 | } |
| 779 | 789 | |
| 780 | 790 | /// Remove values from the beginning of a slice. |
src-self-hosted/TypedValue.zig+1-1| ... | ... | @@ -16,7 +16,7 @@ pub const Managed = struct { |
| 16 | 16 | /// If this is `null` then there is no memory management needed. |
| 17 | 17 | arena: ?*std.heap.ArenaAllocator.State = null, |
| 18 | 18 | |
| 19 | pub fn deinit(self: *ManagedTypedValue, allocator: *Allocator) void { | |
| 19 | pub fn deinit(self: *Managed, allocator: *Allocator) void { | |
| 20 | 20 | if (self.arena) |a| a.promote(allocator).deinit(); |
| 21 | 21 | self.* = undefined; |
| 22 | 22 | } |
src-self-hosted/codegen.zig+2-1| ... | ... | @@ -4,10 +4,11 @@ const assert = std.debug.assert; |
| 4 | 4 | const ir = @import("ir.zig"); |
| 5 | 5 | const Type = @import("type.zig").Type; |
| 6 | 6 | const Value = @import("value.zig").Value; |
| 7 | const TypedValue = @import("TypedValue.zig"); | |
| 7 | 8 | const Target = std.Target; |
| 8 | 9 | const Allocator = mem.Allocator; |
| 9 | 10 | |
| 10 | pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.ArrayList(u8)) !?*ir.ErrorMsg { | |
| 11 | pub fn generateSymbol(typed_value: TypedValue, module: ir.Module, code: *std.ArrayList(u8)) !?*ir.ErrorMsg { | |
| 11 | 12 | switch (typed_value.ty.zigTypeTag()) { |
| 12 | 13 | .Fn => { |
| 13 | 14 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; |
src-self-hosted/ir.zig+272-158| ... | ... | @@ -196,11 +196,9 @@ pub const Module = struct { |
| 196 | 196 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 197 | 197 | /// error messages and mapping outside of `Decl`. |
| 198 | 198 | /// The ErrorMsg memory is owned by the decl, using Module's allocator. |
| 199 | /// Note that a Decl can succeed but the Fn it represents can fail. In this case, | |
| 200 | /// a Decl can have a failed_decls entry but have analysis status of success. | |
| 199 | 201 | failed_decls: std.AutoHashMap(*Decl, *ErrorMsg), |
| 200 | /// We optimize memory usage for a compilation with no compile errors by storing the | |
| 201 | /// error messages and mapping outside of `Fn`. | |
| 202 | /// The ErrorMsg memory is owned by the `Fn`, using Module's allocator. | |
| 203 | failed_fns: std.AutoHashMap(*Fn, *ErrorMsg), | |
| 204 | 202 | /// Using a map here for consistency with the other fields here. |
| 205 | 203 | /// The ErrorMsg memory is owned by the `Scope.ZIRModule`, using Module's allocator. |
| 206 | 204 | failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg), |
| ... | ... | @@ -221,7 +219,14 @@ pub const Module = struct { |
| 221 | 219 | link: link.ElfFile.Export, |
| 222 | 220 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. |
| 223 | 221 | owner_decl: *Decl, |
| 224 | status: enum { in_progress, failed, complete }, | |
| 222 | status: enum { | |
| 223 | in_progress, | |
| 224 | failed, | |
| 225 | /// Indicates that the failure was due to a temporary issue, such as an I/O error | |
| 226 | /// when writing to the output file. Retrying the export may succeed. | |
| 227 | failed_retryable, | |
| 228 | complete, | |
| 229 | }, | |
| 225 | 230 | }; |
| 226 | 231 | |
| 227 | 232 | pub const Decl = struct { |
| ... | ... | @@ -260,6 +265,11 @@ pub const Module = struct { |
| 260 | 265 | /// In this case the `typed_value.most_recent` can still be accessed. |
| 261 | 266 | /// There will be a corresponding ErrorMsg in Module.failed_decls. |
| 262 | 267 | codegen_failure, |
| 268 | /// In this case the `typed_value.most_recent` can still be accessed. | |
| 269 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | |
| 270 | /// This indicates the failure was something like running out of disk space, | |
| 271 | /// and attempting codegen again may succeed. | |
| 272 | codegen_failure_retryable, | |
| 263 | 273 | /// This Decl might be OK but it depends on another one which did not successfully complete |
| 264 | 274 | /// semantic analysis. There is a most recent value available. |
| 265 | 275 | repeat_dependency_failure, |
| ... | ... | @@ -280,40 +290,63 @@ pub const Module = struct { |
| 280 | 290 | /// The shallow set of other decls whose typed_value could possibly change if this Decl's |
| 281 | 291 | /// typed_value is modified. |
| 282 | 292 | /// TODO look into using a lightweight map/set data structure rather than a linear array. |
| 283 | dependants: ArrayListUnmanaged(*Decl) = .{}, | |
| 284 | ||
| 285 | pub fn typedValue(self: Decl) ?TypedValue { | |
| 286 | switch (self.analysis) { | |
| 287 | .initial_in_progress, | |
| 288 | .initial_dependency_failure, | |
| 289 | .initial_sema_failure, | |
| 290 | => return null, | |
| 291 | .codegen_failure, | |
| 292 | .repeat_dependency_failure, | |
| 293 | .repeat_sema_failure, | |
| 294 | .repeat_in_progress, | |
| 295 | .complete, | |
| 296 | => return self.typed_value.most_recent, | |
| 297 | } | |
| 298 | } | |
| 293 | dependants: ArrayListUnmanaged(*Decl) = ArrayListUnmanaged(*Decl){}, | |
| 299 | 294 | |
| 300 | 295 | pub fn destroy(self: *Decl, allocator: *Allocator) void { |
| 301 | allocator.free(mem.spanZ(u8, self.name)); | |
| 302 | if (self.typedValue()) |tv| tv.deinit(allocator); | |
| 296 | allocator.free(mem.spanZ(self.name)); | |
| 297 | if (self.typedValueManaged()) |tvm| { | |
| 298 | tvm.deinit(allocator); | |
| 299 | } | |
| 303 | 300 | allocator.destroy(self); |
| 304 | 301 | } |
| 305 | 302 | |
| 306 | 303 | pub const Hash = [16]u8; |
| 307 | 304 | |
| 305 | /// If the name is small enough, it is used directly as the hash. | |
| 306 | /// If it is long, blake3 hash is computed. | |
| 307 | pub fn hashSimpleName(name: []const u8) Hash { | |
| 308 | var out: Hash = undefined; | |
| 309 | if (name.len <= Hash.len) { | |
| 310 | mem.copy(u8, &out, name); | |
| 311 | mem.set(u8, out[name.len..], 0); | |
| 312 | } else { | |
| 313 | std.crypto.Blake3.hash(name, &out); | |
| 314 | } | |
| 315 | return out; | |
| 316 | } | |
| 317 | ||
| 308 | 318 | /// Must generate unique bytes with no collisions with other decls. |
| 309 | 319 | /// The point of hashing here is only to limit the number of bytes of |
| 310 | 320 | /// the unique identifier to a fixed size (16 bytes). |
| 311 | 321 | pub fn fullyQualifiedNameHash(self: Decl) Hash { |
| 312 | 322 | // Right now we only have ZIRModule as the source. So this is simply the |
| 313 | 323 | // relative name of the decl. |
| 314 | var out: Hash = undefined; | |
| 315 | std.crypto.Blake3.hash(mem.spanZ(u8, self.name), &out); | |
| 316 | return out; | |
| 324 | return hashSimpleName(mem.spanZ(u8, self.name)); | |
| 325 | } | |
| 326 | ||
| 327 | pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue { | |
| 328 | const tvm = self.typedValueManaged() orelse return error.AnalysisFail; | |
| 329 | return tvm.typed_value; | |
| 330 | } | |
| 331 | ||
| 332 | pub fn value(self: *Decl) error{AnalysisFail}!Value { | |
| 333 | return (try self.typedValue()).val; | |
| 334 | } | |
| 335 | ||
| 336 | fn typedValueManaged(self: *Decl) ?*TypedValue.Managed { | |
| 337 | switch (self.analysis) { | |
| 338 | .initial_in_progress, | |
| 339 | .initial_dependency_failure, | |
| 340 | .initial_sema_failure, | |
| 341 | => return null, | |
| 342 | .codegen_failure, | |
| 343 | .codegen_failure_retryable, | |
| 344 | .repeat_dependency_failure, | |
| 345 | .repeat_sema_failure, | |
| 346 | .repeat_in_progress, | |
| 347 | .complete, | |
| 348 | => return &self.typed_value.most_recent, | |
| 349 | } | |
| 317 | 350 | } |
| 318 | 351 | }; |
| 319 | 352 | |
| ... | ... | @@ -325,22 +358,19 @@ pub const Module = struct { |
| 325 | 358 | /// The value is the source instruction. |
| 326 | 359 | queued: *text.Inst.Fn, |
| 327 | 360 | in_progress: *Analysis, |
| 328 | /// There will be a corresponding ErrorMsg in Module.failed_fns | |
| 361 | /// There will be a corresponding ErrorMsg in Module.failed_decls | |
| 329 | 362 | failure, |
| 330 | 363 | success: Body, |
| 331 | 364 | }, |
| 332 | /// The direct container of the Fn. This field will need to get more fleshed out when | |
| 333 | /// self-hosted supports proper struct types and Zig AST => ZIR. | |
| 334 | scope: *Scope.ZIRModule, | |
| 335 | 365 | |
| 336 | 366 | /// This memory is temporary and points to stack memory for the duration |
| 337 | 367 | /// of Fn analysis. |
| 338 | 368 | pub const Analysis = struct { |
| 339 | 369 | inner_block: Scope.Block, |
| 340 | /// null value means a semantic analysis error happened. | |
| 341 | inst_table: std.AutoHashMap(*text.Inst, ?*Inst), | |
| 342 | /// Owns the memory for instructions | |
| 343 | arena: std.heap.ArenaAllocator, | |
| 370 | /// TODO Performance optimization idea: instead of this inst_table, | |
| 371 | /// use a field in the text.Inst instead to track corresponding instructions | |
| 372 | inst_table: std.AutoHashMap(*text.Inst, *Inst), | |
| 373 | needed_inst_capacity: usize, | |
| 344 | 374 | }; |
| 345 | 375 | }; |
| 346 | 376 | |
| ... | ... | @@ -374,6 +404,16 @@ pub const Module = struct { |
| 374 | 404 | } |
| 375 | 405 | } |
| 376 | 406 | |
| 407 | /// Asserts the scope has a parent which is a ZIRModule and | |
| 408 | /// returns it. | |
| 409 | pub fn namespace(self: *Scope) *ZIRModule { | |
| 410 | switch (self.tag) { | |
| 411 | .block => return self.cast(Block).?.decl.scope, | |
| 412 | .decl => return self.cast(DeclAnalysis).?.decl.scope, | |
| 413 | .zir_module => return self.cast(ZIRModule).?, | |
| 414 | } | |
| 415 | } | |
| 416 | ||
| 377 | 417 | pub const Tag = enum { |
| 378 | 418 | zir_module, |
| 379 | 419 | block, |
| ... | ... | @@ -407,11 +447,11 @@ pub const Module = struct { |
| 407 | 447 | .unloaded_parse_failure, |
| 408 | 448 | => {}, |
| 409 | 449 | .loaded_success => { |
| 410 | allocator.free(contents.source); | |
| 450 | allocator.free(self.source.bytes); | |
| 411 | 451 | self.contents.module.deinit(allocator); |
| 412 | 452 | }, |
| 413 | 453 | .loaded_parse_failure => { |
| 414 | allocator.free(contents.source); | |
| 454 | allocator.free(self.source.bytes); | |
| 415 | 455 | }, |
| 416 | 456 | } |
| 417 | 457 | self.* = undefined; |
| ... | ... | @@ -469,8 +509,8 @@ pub const Module = struct { |
| 469 | 509 | ) !void { |
| 470 | 510 | const loc = std.zig.findLineColumn(source, simple_err_msg.byte_offset); |
| 471 | 511 | try errors.append(.{ |
| 472 | .src_path = try mem.dupe(u8, &arena.allocator, sub_file_path), | |
| 473 | .msg = try mem.dupe(u8, &arena.allocator, simple_err_msg.msg), | |
| 512 | .src_path = try arena.allocator.dupe(u8, sub_file_path), | |
| 513 | .msg = try arena.allocator.dupe(u8, simple_err_msg.msg), | |
| 474 | 514 | .byte_offset = simple_err_msg.byte_offset, |
| 475 | 515 | .line = loc.line, |
| 476 | 516 | .column = loc.column, |
| ... | ... | @@ -480,7 +520,7 @@ pub const Module = struct { |
| 480 | 520 | |
| 481 | 521 | pub fn deinit(self: *Module) void { |
| 482 | 522 | const allocator = self.allocator; |
| 483 | allocator.free(self.errors); | |
| 523 | self.work_stack.deinit(allocator); | |
| 484 | 524 | { |
| 485 | 525 | var it = self.decl_table.iterator(); |
| 486 | 526 | while (it.next()) |kv| { |
| ... | ... | @@ -488,8 +528,44 @@ pub const Module = struct { |
| 488 | 528 | } |
| 489 | 529 | self.decl_table.deinit(); |
| 490 | 530 | } |
| 531 | { | |
| 532 | var it = self.failed_decls.iterator(); | |
| 533 | while (it.next()) |kv| { | |
| 534 | kv.value.destroy(allocator); | |
| 535 | } | |
| 536 | self.failed_decls.deinit(); | |
| 537 | } | |
| 538 | { | |
| 539 | var it = self.failed_files.iterator(); | |
| 540 | while (it.next()) |kv| { | |
| 541 | kv.value.destroy(allocator); | |
| 542 | } | |
| 543 | self.failed_files.deinit(); | |
| 544 | } | |
| 545 | { | |
| 546 | var it = self.failed_exports.iterator(); | |
| 547 | while (it.next()) |kv| { | |
| 548 | kv.value.destroy(allocator); | |
| 549 | } | |
| 550 | self.failed_exports.deinit(); | |
| 551 | } | |
| 552 | self.decl_exports.deinit(); | |
| 553 | { | |
| 554 | var it = self.export_owners.iterator(); | |
| 555 | while (it.next()) |kv| { | |
| 556 | const export_list = kv.value; | |
| 557 | for (export_list) |exp| { | |
| 558 | allocator.destroy(exp); | |
| 559 | } | |
| 560 | allocator.free(export_list); | |
| 561 | } | |
| 562 | self.failed_exports.deinit(); | |
| 563 | } | |
| 491 | 564 | self.root_pkg.destroy(); |
| 492 | self.root_scope.deinit(); | |
| 565 | { | |
| 566 | self.root_scope.deinit(allocator); | |
| 567 | allocator.destroy(self.root_scope); | |
| 568 | } | |
| 493 | 569 | self.* = undefined; |
| 494 | 570 | } |
| 495 | 571 | |
| ... | ... | @@ -504,19 +580,20 @@ pub const Module = struct { |
| 504 | 580 | // Analyze the root source file now. |
| 505 | 581 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { |
| 506 | 582 | error.AnalysisFail => { |
| 507 | assert(self.failed_files.size != 0); | |
| 583 | assert(self.totalErrorCount() != 0); | |
| 508 | 584 | }, |
| 509 | 585 | else => |e| return e, |
| 510 | 586 | }; |
| 511 | 587 | |
| 588 | try self.performAllTheWork(); | |
| 589 | ||
| 512 | 590 | try self.bin_file.flush(); |
| 513 | 591 | self.link_error_flags = self.bin_file.error_flags; |
| 514 | 592 | } |
| 515 | 593 | |
| 516 | 594 | pub fn totalErrorCount(self: *Module) usize { |
| 517 | 595 | return self.failed_decls.size + |
| 518 | self.failed_fns.size + | |
| 519 | self.failed_decls.size + | |
| 596 | self.failed_files.size + | |
| 520 | 597 | self.failed_exports.size + |
| 521 | 598 | @boolToInt(self.link_error_flags.no_entry_point_found); |
| 522 | 599 | } |
| ... | ... | @@ -533,17 +610,8 @@ pub const Module = struct { |
| 533 | 610 | while (it.next()) |kv| { |
| 534 | 611 | const scope = kv.key; |
| 535 | 612 | const err_msg = kv.value; |
| 536 | const source = scope.parse_failure.source; | |
| 537 | AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg); | |
| 538 | } | |
| 539 | } | |
| 540 | { | |
| 541 | var it = self.failed_fns.iterator(); | |
| 542 | while (it.next()) |kv| { | |
| 543 | const func = kv.key; | |
| 544 | const err_msg = kv.value; | |
| 545 | const source = func.scope.success.source; | |
| 546 | AllErrors.add(&arena, &errors, func.scope.sub_file_path, source, err_msg); | |
| 613 | const source = scope.source.bytes; | |
| 614 | try AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg.*); | |
| 547 | 615 | } |
| 548 | 616 | } |
| 549 | 617 | { |
| ... | ... | @@ -551,8 +619,8 @@ pub const Module = struct { |
| 551 | 619 | while (it.next()) |kv| { |
| 552 | 620 | const decl = kv.key; |
| 553 | 621 | const err_msg = kv.value; |
| 554 | const source = decl.scope.success.source; | |
| 555 | AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg); | |
| 622 | const source = decl.scope.source.bytes; | |
| 623 | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*); | |
| 556 | 624 | } |
| 557 | 625 | } |
| 558 | 626 | { |
| ... | ... | @@ -560,14 +628,14 @@ pub const Module = struct { |
| 560 | 628 | while (it.next()) |kv| { |
| 561 | 629 | const decl = kv.key.owner_decl; |
| 562 | 630 | const err_msg = kv.value; |
| 563 | const source = decl.scope.success.source; | |
| 564 | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg); | |
| 631 | const source = decl.scope.source.bytes; | |
| 632 | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*); | |
| 565 | 633 | } |
| 566 | 634 | } |
| 567 | 635 | |
| 568 | 636 | if (self.link_error_flags.no_entry_point_found) { |
| 569 | 637 | try errors.append(.{ |
| 570 | .src_path = self.module.root_src_path, | |
| 638 | .src_path = self.root_pkg.root_src_path, | |
| 571 | 639 | .line = 0, |
| 572 | 640 | .column = 0, |
| 573 | 641 | .byte_offset = 0, |
| ... | ... | @@ -579,12 +647,56 @@ pub const Module = struct { |
| 579 | 647 | |
| 580 | 648 | return AllErrors{ |
| 581 | 649 | .arena = arena.state, |
| 582 | .list = try mem.dupe(&arena.allocator, AllErrors.Message, errors.items), | |
| 650 | .list = try arena.allocator.dupe(AllErrors.Message, errors.items), | |
| 583 | 651 | }; |
| 584 | 652 | } |
| 585 | 653 | |
| 586 | 654 | const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 587 | 655 | |
| 656 | pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { | |
| 657 | while (self.work_stack.popOrNull()) |work_item| switch (work_item) { | |
| 658 | .codegen_decl => |decl| switch (decl.analysis) { | |
| 659 | .initial_in_progress, | |
| 660 | .repeat_in_progress, | |
| 661 | => unreachable, | |
| 662 | ||
| 663 | .initial_sema_failure, | |
| 664 | .repeat_sema_failure, | |
| 665 | .codegen_failure, | |
| 666 | .initial_dependency_failure, | |
| 667 | .repeat_dependency_failure, | |
| 668 | => continue, | |
| 669 | ||
| 670 | .complete, .codegen_failure_retryable => { | |
| 671 | if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| { | |
| 672 | switch (payload.func.analysis) { | |
| 673 | .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) { | |
| 674 | error.AnalysisFail => continue, | |
| 675 | else => |e| return e, | |
| 676 | }, | |
| 677 | .in_progress => unreachable, | |
| 678 | .failure => continue, | |
| 679 | .success => {}, | |
| 680 | } | |
| 681 | } | |
| 682 | self.bin_file.updateDecl(self, decl) catch |err| switch (err) { | |
| 683 | error.OutOfMemory => return error.OutOfMemory, | |
| 684 | else => { | |
| 685 | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); | |
| 686 | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( | |
| 687 | self.allocator, | |
| 688 | decl.src, | |
| 689 | "unable to codegen: {}", | |
| 690 | .{@errorName(err)}, | |
| 691 | )); | |
| 692 | decl.analysis = .codegen_failure_retryable; | |
| 693 | }, | |
| 694 | }; | |
| 695 | }, | |
| 696 | }, | |
| 697 | }; | |
| 698 | } | |
| 699 | ||
| 588 | 700 | fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 589 | 701 | // TODO use the cache to identify, from the modified source files, the decls which have |
| 590 | 702 | // changed based on the span of memory that represents the decl in the re-parsed source file. |
| ... | ... | @@ -650,56 +762,39 @@ pub const Module = struct { |
| 650 | 762 | try analyzeExport(self, &root_scope.base, export_inst); |
| 651 | 763 | } |
| 652 | 764 | } |
| 653 | ||
| 654 | while (self.work_stack.pop()) |work_item| switch (work_item) { | |
| 655 | .codegen_decl => |decl| switch (decl.analysis) { | |
| 656 | .success => { | |
| 657 | if (decl.typed_value.most_recent.typed_value.val.cast(Value.Function)) |payload| { | |
| 658 | switch (payload.func.analysis) { | |
| 659 | .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) { | |
| 660 | error.AnalysisFail => { | |
| 661 | assert(func_payload.func.analysis == .failure); | |
| 662 | continue; | |
| 663 | }, | |
| 664 | else => |e| return e, | |
| 665 | }, | |
| 666 | .in_progress => unreachable, | |
| 667 | .failure => continue, | |
| 668 | .success => {}, | |
| 669 | } | |
| 670 | } | |
| 671 | try self.bin_file.updateDecl(self, decl); | |
| 672 | }, | |
| 673 | }, | |
| 674 | }; | |
| 675 | 765 | } |
| 676 | 766 | |
| 677 | 767 | fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 678 | 768 | // Use the Decl's arena for function memory. |
| 679 | 769 | var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator); |
| 680 | 770 | defer decl.typed_value.most_recent.arena.?.* = arena.state; |
| 681 | var analysis: Analysis = .{ | |
| 771 | var analysis: Fn.Analysis = .{ | |
| 682 | 772 | .inner_block = .{ |
| 683 | 773 | .func = func, |
| 684 | 774 | .decl = decl, |
| 685 | 775 | .instructions = .{}, |
| 686 | 776 | .arena = &arena.allocator, |
| 687 | 777 | }, |
| 688 | .inst_table = std.AutoHashMap(*text.Inst, ?*Inst).init(self.allocator), | |
| 778 | .needed_inst_capacity = 0, | |
| 779 | .inst_table = std.AutoHashMap(*text.Inst, *Inst).init(self.allocator), | |
| 689 | 780 | }; |
| 690 | defer analysis.inner_block.instructions.deinit(); | |
| 781 | defer analysis.inner_block.instructions.deinit(self.allocator); | |
| 691 | 782 | defer analysis.inst_table.deinit(); |
| 692 | 783 | |
| 693 | 784 | const fn_inst = func.analysis.queued; |
| 694 | 785 | func.analysis = .{ .in_progress = &analysis }; |
| 695 | 786 | |
| 696 | try self.analyzeBody(&analysis.inner_block, fn_inst.positionals.body); | |
| 787 | try self.analyzeBody(&analysis.inner_block.base, fn_inst.positionals.body); | |
| 697 | 788 | |
| 698 | func.analysis = .{ .success = .{ .instructions = analysis.inner_block.instructions.toOwnedSlice() } }; | |
| 789 | func.analysis = .{ | |
| 790 | .success = .{ | |
| 791 | .instructions = try arena.allocator.dupe(*Inst, analysis.inner_block.instructions.items), | |
| 792 | }, | |
| 793 | }; | |
| 699 | 794 | } |
| 700 | 795 | |
| 701 | 796 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { |
| 702 | const hash = old_inst.fullyQualifiedNameHash(); | |
| 797 | const hash = Decl.hashSimpleName(old_inst.name); | |
| 703 | 798 | if (self.decl_table.get(hash)) |kv| { |
| 704 | 799 | return kv.value; |
| 705 | 800 | } else { |
| ... | ... | @@ -711,7 +806,7 @@ pub const Module = struct { |
| 711 | 806 | errdefer self.allocator.free(name); |
| 712 | 807 | new_decl.* = .{ |
| 713 | 808 | .name = name, |
| 714 | .scope = scope.findZIRModule(), | |
| 809 | .scope = scope.namespace(), | |
| 715 | 810 | .src = old_inst.src, |
| 716 | 811 | .typed_value = .{ .never_succeeded = {} }, |
| 717 | 812 | .analysis = .initial_in_progress, |
| ... | ... | @@ -726,12 +821,11 @@ pub const Module = struct { |
| 726 | 821 | }; |
| 727 | 822 | errdefer decl_scope.arena.deinit(); |
| 728 | 823 | |
| 729 | const arena_state = try self.allocator.create(std.heap.ArenaAllocator.State); | |
| 730 | errdefer self.allocator.destroy(arena_state); | |
| 824 | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); | |
| 731 | 825 | |
| 732 | 826 | const typed_value = try self.analyzeInstConst(&decl_scope.base, old_inst); |
| 733 | 827 | |
| 734 | arena_state.* = decl_scope.arena; | |
| 828 | arena_state.* = decl_scope.arena.state; | |
| 735 | 829 | |
| 736 | 830 | new_decl.typed_value = .{ |
| 737 | 831 | .most_recent = .{ |
| ... | ... | @@ -741,7 +835,7 @@ pub const Module = struct { |
| 741 | 835 | }; |
| 742 | 836 | new_decl.analysis = .complete; |
| 743 | 837 | // We ensureCapacity when scanning for decls. |
| 744 | self.work_stack.appendAssumeCapacity(self.allocator, .{ .codegen_decl = new_decl }); | |
| 838 | self.work_stack.appendAssumeCapacity(.{ .codegen_decl = new_decl }); | |
| 745 | 839 | return new_decl; |
| 746 | 840 | } |
| 747 | 841 | } |
| ... | ... | @@ -756,6 +850,7 @@ pub const Module = struct { |
| 756 | 850 | .initial_sema_failure, |
| 757 | 851 | .repeat_sema_failure, |
| 758 | 852 | .codegen_failure, |
| 853 | .codegen_failure_retryable, | |
| 759 | 854 | => return error.AnalysisFail, |
| 760 | 855 | |
| 761 | 856 | .complete => return decl, |
| ... | ... | @@ -764,14 +859,14 @@ pub const Module = struct { |
| 764 | 859 | |
| 765 | 860 | fn resolveInst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Inst { |
| 766 | 861 | if (scope.cast(Scope.Block)) |block| { |
| 767 | if (block.func.inst_table.get(old_inst)) |kv| { | |
| 768 | return kv.value.ptr orelse return error.AnalysisFail; | |
| 862 | if (block.func.analysis.in_progress.inst_table.get(old_inst)) |kv| { | |
| 863 | return kv.value; | |
| 769 | 864 | } |
| 770 | 865 | } |
| 771 | 866 | |
| 772 | 867 | const decl = try self.resolveCompleteDecl(scope, old_inst); |
| 773 | 868 | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); |
| 774 | return self.analyzeDeref(scope, old_inst.src, decl_ref); | |
| 869 | return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src); | |
| 775 | 870 | } |
| 776 | 871 | |
| 777 | 872 | fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| ... | ... | @@ -819,7 +914,7 @@ pub const Module = struct { |
| 819 | 914 | return val.toType(); |
| 820 | 915 | } |
| 821 | 916 | |
| 822 | fn analyzeExport(self: *Module, scope: *Scope, export_inst: *text.Inst.Export) !void { | |
| 917 | fn analyzeExport(self: *Module, scope: *Scope, export_inst: *text.Inst.Export) InnerError!void { | |
| 823 | 918 | try self.decl_exports.ensureCapacity(self.decl_exports.size + 1); |
| 824 | 919 | try self.export_owners.ensureCapacity(self.export_owners.size + 1); |
| 825 | 920 | const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name); |
| ... | ... | @@ -840,7 +935,7 @@ pub const Module = struct { |
| 840 | 935 | const owner_decl = scope.decl(); |
| 841 | 936 | |
| 842 | 937 | new_export.* = .{ |
| 843 | .options = .{ .data = .{ .name = symbol_name } }, | |
| 938 | .options = .{ .name = symbol_name }, | |
| 844 | 939 | .src = export_inst.base.src, |
| 845 | 940 | .link = .{}, |
| 846 | 941 | .owner_decl = owner_decl, |
| ... | ... | @@ -865,7 +960,19 @@ pub const Module = struct { |
| 865 | 960 | de_gop.kv.value[de_gop.kv.value.len - 1] = new_export; |
| 866 | 961 | errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1); |
| 867 | 962 | |
| 868 | try self.bin_file.updateDeclExports(self, decl, de_gop.kv.value); | |
| 963 | self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) { | |
| 964 | error.OutOfMemory => return error.OutOfMemory, | |
| 965 | else => { | |
| 966 | try self.failed_exports.ensureCapacity(self.failed_exports.size + 1); | |
| 967 | self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create( | |
| 968 | self.allocator, | |
| 969 | export_inst.base.src, | |
| 970 | "unable to export: {}", | |
| 971 | .{@errorName(err)}, | |
| 972 | )); | |
| 973 | new_export.status = .failed_retryable; | |
| 974 | }, | |
| 975 | }; | |
| 869 | 976 | } |
| 870 | 977 | |
| 871 | 978 | /// TODO should not need the cast on the last parameter at the callsites |
| ... | ... | @@ -976,7 +1083,7 @@ pub const Module = struct { |
| 976 | 1083 | fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst { |
| 977 | 1084 | const val_payload = if (big_int.positive) blk: { |
| 978 | 1085 | if (big_int.to(u64)) |x| { |
| 979 | return self.constIntUnsigned(src, ty, x); | |
| 1086 | return self.constIntUnsigned(scope, src, ty, x); | |
| 980 | 1087 | } else |err| switch (err) { |
| 981 | 1088 | error.NegativeIntoUnsigned => unreachable, |
| 982 | 1089 | error.TargetTooSmall => {}, // handled below |
| ... | ... | @@ -986,7 +1093,7 @@ pub const Module = struct { |
| 986 | 1093 | break :blk &big_int_payload.base; |
| 987 | 1094 | } else blk: { |
| 988 | 1095 | if (big_int.to(i64)) |x| { |
| 989 | return self.constIntSigned(src, ty, x); | |
| 1096 | return self.constIntSigned(scope, src, ty, x); | |
| 990 | 1097 | } else |err| switch (err) { |
| 991 | 1098 | error.NegativeIntoUnsigned => unreachable, |
| 992 | 1099 | error.TargetTooSmall => {}, // handled below |
| ... | ... | @@ -1014,15 +1121,17 @@ pub const Module = struct { |
| 1014 | 1121 | switch (old_inst.tag) { |
| 1015 | 1122 | .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(text.Inst.Breakpoint).?), |
| 1016 | 1123 | .call => return self.analyzeInstCall(scope, old_inst.cast(text.Inst.Call).?), |
| 1124 | .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(text.Inst.DeclRef).?), | |
| 1017 | 1125 | .str => { |
| 1018 | // We can use this reference because Inst.Const's Value is arena-allocated. | |
| 1019 | // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends. | |
| 1020 | 1126 | const bytes = old_inst.cast(text.Inst.Str).?.positionals.bytes; |
| 1021 | return self.constStr(old_inst.src, bytes); | |
| 1127 | // The bytes references memory inside the ZIR text module, which can get deallocated | |
| 1128 | // after semantic analysis is complete. We need the memory to be in the Decl's arena. | |
| 1129 | const arena_bytes = try scope.arena().dupe(u8, bytes); | |
| 1130 | return self.constStr(scope, old_inst.src, arena_bytes); | |
| 1022 | 1131 | }, |
| 1023 | 1132 | .int => { |
| 1024 | 1133 | const big_int = old_inst.cast(text.Inst.Int).?.positionals.int; |
| 1025 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); | |
| 1134 | return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int); | |
| 1026 | 1135 | }, |
| 1027 | 1136 | .ptrtoint => return self.analyzeInstPtrToInt(scope, old_inst.cast(text.Inst.PtrToInt).?), |
| 1028 | 1137 | .fieldptr => return self.analyzeInstFieldPtr(scope, old_inst.cast(text.Inst.FieldPtr).?), |
| ... | ... | @@ -1036,7 +1145,7 @@ pub const Module = struct { |
| 1036 | 1145 | try self.analyzeExport(scope, old_inst.cast(text.Inst.Export).?); |
| 1037 | 1146 | return self.constVoid(scope, old_inst.src); |
| 1038 | 1147 | }, |
| 1039 | .primitive => return self.analyzeInstPrimitive(old_inst.cast(text.Inst.Primitive).?), | |
| 1148 | .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(text.Inst.Primitive).?), | |
| 1040 | 1149 | .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?), |
| 1041 | 1150 | .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(text.Inst.IntCast).?), |
| 1042 | 1151 | .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(text.Inst.BitCast).?), |
| ... | ... | @@ -1054,6 +1163,14 @@ pub const Module = struct { |
| 1054 | 1163 | return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){}); |
| 1055 | 1164 | } |
| 1056 | 1165 | |
| 1166 | fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *text.Inst.DeclRef) InnerError!*Inst { | |
| 1167 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstDeclFef", .{}); | |
| 1168 | } | |
| 1169 | ||
| 1170 | fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst { | |
| 1171 | return self.fail(scope, src, "TODO implement analyzeDeclRef", .{}); | |
| 1172 | } | |
| 1173 | ||
| 1057 | 1174 | fn analyzeInstCall(self: *Module, scope: *Scope, inst: *text.Inst.Call) InnerError!*Inst { |
| 1058 | 1175 | const func = try self.resolveInst(scope, inst.positionals.func); |
| 1059 | 1176 | if (func.ty.zigTypeTag() != .Fn) |
| ... | ... | @@ -1123,8 +1240,7 @@ pub const Module = struct { |
| 1123 | 1240 | const new_func = try scope.arena().create(Fn); |
| 1124 | 1241 | new_func.* = .{ |
| 1125 | 1242 | .fn_type = fn_type, |
| 1126 | .analysis = .{ .queued = fn_inst.positionals.body }, | |
| 1127 | .scope = scope.namespace(), | |
| 1243 | .analysis = .{ .queued = fn_inst }, | |
| 1128 | 1244 | }; |
| 1129 | 1245 | const fn_payload = try scope.arena().create(Value.Payload.Function); |
| 1130 | 1246 | fn_payload.* = .{ .func = new_func }; |
| ... | ... | @@ -1141,28 +1257,28 @@ pub const Module = struct { |
| 1141 | 1257 | fntype.positionals.param_types.len == 0 and |
| 1142 | 1258 | fntype.kw_args.cc == .Unspecified) |
| 1143 | 1259 | { |
| 1144 | return self.constType(fntype.base.src, Type.initTag(.fn_noreturn_no_args)); | |
| 1260 | return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args)); | |
| 1145 | 1261 | } |
| 1146 | 1262 | |
| 1147 | 1263 | if (return_type.zigTypeTag() == .NoReturn and |
| 1148 | 1264 | fntype.positionals.param_types.len == 0 and |
| 1149 | 1265 | fntype.kw_args.cc == .Naked) |
| 1150 | 1266 | { |
| 1151 | return self.constType(fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); | |
| 1267 | return self.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); | |
| 1152 | 1268 | } |
| 1153 | 1269 | |
| 1154 | 1270 | if (return_type.zigTypeTag() == .Void and |
| 1155 | 1271 | fntype.positionals.param_types.len == 0 and |
| 1156 | 1272 | fntype.kw_args.cc == .C) |
| 1157 | 1273 | { |
| 1158 | return self.constType(fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); | |
| 1274 | return self.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); | |
| 1159 | 1275 | } |
| 1160 | 1276 | |
| 1161 | 1277 | return self.fail(scope, fntype.base.src, "TODO implement fntype instruction more", .{}); |
| 1162 | 1278 | } |
| 1163 | 1279 | |
| 1164 | fn analyzeInstPrimitive(self: *Module, primitive: *text.Inst.Primitive) InnerError!*Inst { | |
| 1165 | return self.constType(primitive.base.src, primitive.positionals.tag.toType()); | |
| 1280 | fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *text.Inst.Primitive) InnerError!*Inst { | |
| 1281 | return self.constType(scope, primitive.base.src, primitive.positionals.tag.toType()); | |
| 1166 | 1282 | } |
| 1167 | 1283 | |
| 1168 | 1284 | fn analyzeInstAs(self: *Module, scope: *Scope, as: *text.Inst.As) InnerError!*Inst { |
| ... | ... | @@ -1332,18 +1448,22 @@ pub const Module = struct { |
| 1332 | 1448 | |
| 1333 | 1449 | fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *text.Inst.Deref) InnerError!*Inst { |
| 1334 | 1450 | const ptr = try self.resolveInst(scope, deref.positionals.ptr); |
| 1451 | return self.analyzeDeref(scope, deref.base.src, ptr, deref.positionals.ptr.src); | |
| 1452 | } | |
| 1453 | ||
| 1454 | fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { | |
| 1335 | 1455 | const elem_ty = switch (ptr.ty.zigTypeTag()) { |
| 1336 | 1456 | .Pointer => ptr.ty.elemType(), |
| 1337 | else => return self.fail(scope, deref.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}), | |
| 1457 | else => return self.fail(scope, ptr_src, "expected pointer, found '{}'", .{ptr.ty}), | |
| 1338 | 1458 | }; |
| 1339 | 1459 | if (ptr.value()) |val| { |
| 1340 | return self.constInst(scope, deref.base.src, .{ | |
| 1460 | return self.constInst(scope, src, .{ | |
| 1341 | 1461 | .ty = elem_ty, |
| 1342 | .val = val.pointerDeref(), | |
| 1462 | .val = try val.pointerDeref(scope.arena()), | |
| 1343 | 1463 | }); |
| 1344 | 1464 | } |
| 1345 | 1465 | |
| 1346 | return self.fail(scope, deref.base.src, "TODO implement runtime deref", .{}); | |
| 1466 | return self.fail(scope, src, "TODO implement runtime deref", .{}); | |
| 1347 | 1467 | } |
| 1348 | 1468 | |
| 1349 | 1469 | fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *text.Inst.Asm) InnerError!*Inst { |
| ... | ... | @@ -1390,7 +1510,7 @@ pub const Module = struct { |
| 1390 | 1510 | const rhs_ty_tag = rhs.ty.zigTypeTag(); |
| 1391 | 1511 | if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) { |
| 1392 | 1512 | // null == null, null != null |
| 1393 | return self.constBool(inst.base.src, op == .eq); | |
| 1513 | return self.constBool(scope, inst.base.src, op == .eq); | |
| 1394 | 1514 | } else if (is_equality_cmp and |
| 1395 | 1515 | ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or |
| 1396 | 1516 | rhs_ty_tag == .Null and lhs_ty_tag == .Optional)) |
| ... | ... | @@ -1399,7 +1519,7 @@ pub const Module = struct { |
| 1399 | 1519 | const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs; |
| 1400 | 1520 | if (opt_operand.value()) |opt_val| { |
| 1401 | 1521 | const is_null = opt_val.isNull(); |
| 1402 | return self.constBool(inst.base.src, if (op == .eq) is_null else !is_null); | |
| 1522 | return self.constBool(scope, inst.base.src, if (op == .eq) is_null else !is_null); | |
| 1403 | 1523 | } |
| 1404 | 1524 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 1405 | 1525 | switch (op) { |
| ... | ... | @@ -1468,32 +1588,27 @@ pub const Module = struct { |
| 1468 | 1588 | const parent_block = try self.requireRuntimeBlock(scope, inst.base.src); |
| 1469 | 1589 | |
| 1470 | 1590 | var true_block: Scope.Block = .{ |
| 1471 | .base = .{ .parent = scope }, | |
| 1472 | 1591 | .func = parent_block.func, |
| 1592 | .decl = parent_block.decl, | |
| 1473 | 1593 | .instructions = .{}, |
| 1594 | .arena = parent_block.arena, | |
| 1474 | 1595 | }; |
| 1475 | defer true_block.instructions.deinit(); | |
| 1596 | defer true_block.instructions.deinit(self.allocator); | |
| 1476 | 1597 | try self.analyzeBody(&true_block.base, inst.positionals.true_body); |
| 1477 | 1598 | |
| 1478 | 1599 | var false_block: Scope.Block = .{ |
| 1479 | .base = .{ .parent = scope }, | |
| 1480 | 1600 | .func = parent_block.func, |
| 1601 | .decl = parent_block.decl, | |
| 1481 | 1602 | .instructions = .{}, |
| 1603 | .arena = parent_block.arena, | |
| 1482 | 1604 | }; |
| 1483 | defer false_block.instructions.deinit(); | |
| 1605 | defer false_block.instructions.deinit(self.allocator); | |
| 1484 | 1606 | try self.analyzeBody(&false_block.base, inst.positionals.false_body); |
| 1485 | 1607 | |
| 1486 | // Copy the instruction pointers to the arena memory | |
| 1487 | const true_instructions = try scope.arena().alloc(*Inst, true_block.instructions.items.len); | |
| 1488 | const false_instructions = try scope.arena().alloc(*Inst, false_block.instructions.items.len); | |
| 1489 | ||
| 1490 | mem.copy(*Inst, true_instructions, true_block.instructions.items); | |
| 1491 | mem.copy(*Inst, false_instructions, false_block.instructions.items); | |
| 1492 | ||
| 1493 | 1608 | return self.addNewInstArgs(parent_block, inst.base.src, Type.initTag(.void), Inst.CondBr, Inst.Args(Inst.CondBr){ |
| 1494 | 1609 | .condition = cond, |
| 1495 | .true_body = .{ .instructions = true_instructions }, | |
| 1496 | .false_body = .{ .instructions = false_instructions }, | |
| 1610 | .true_body = .{ .instructions = try scope.arena().dupe(*Inst, true_block.instructions.items) }, | |
| 1611 | .false_body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) }, | |
| 1497 | 1612 | }); |
| 1498 | 1613 | } |
| 1499 | 1614 | |
| ... | ... | @@ -1521,15 +1636,18 @@ pub const Module = struct { |
| 1521 | 1636 | } |
| 1522 | 1637 | |
| 1523 | 1638 | fn analyzeBody(self: *Module, scope: *Scope, body: text.Module.Body) !void { |
| 1524 | for (body.instructions) |src_inst| { | |
| 1525 | const new_inst = self.analyzeInst(scope, src_inst) catch |err| { | |
| 1526 | if (scope.cast(Scope.Block)) |b| { | |
| 1527 | self.fns.items[b.func.fn_index].analysis_status = .failure; | |
| 1528 | try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = null }); | |
| 1529 | } | |
| 1530 | return err; | |
| 1531 | }; | |
| 1532 | if (scope.cast(Scope.Block)) |b| try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst }); | |
| 1639 | if (scope.cast(Scope.Block)) |b| { | |
| 1640 | const analysis = b.func.analysis.in_progress; | |
| 1641 | analysis.needed_inst_capacity += body.instructions.len; | |
| 1642 | try analysis.inst_table.ensureCapacity(analysis.needed_inst_capacity); | |
| 1643 | for (body.instructions) |src_inst| { | |
| 1644 | const new_inst = try self.analyzeInst(scope, src_inst); | |
| 1645 | analysis.inst_table.putAssumeCapacityNoClobber(src_inst, new_inst); | |
| 1646 | } | |
| 1647 | } else { | |
| 1648 | for (body.instructions) |src_inst| { | |
| 1649 | _ = try self.analyzeInst(scope, src_inst); | |
| 1650 | } | |
| 1533 | 1651 | } |
| 1534 | 1652 | } |
| 1535 | 1653 | |
| ... | ... | @@ -1575,7 +1693,7 @@ pub const Module = struct { |
| 1575 | 1693 | |
| 1576 | 1694 | if (lhs.value()) |lhs_val| { |
| 1577 | 1695 | if (rhs.value()) |rhs_val| { |
| 1578 | return self.constBool(src, Value.compare(lhs_val, op, rhs_val)); | |
| 1696 | return self.constBool(scope, src, Value.compare(lhs_val, op, rhs_val)); | |
| 1579 | 1697 | } |
| 1580 | 1698 | } |
| 1581 | 1699 | |
| ... | ... | @@ -1647,8 +1765,8 @@ pub const Module = struct { |
| 1647 | 1765 | const zcmp = lhs_val.orderAgainstZero(); |
| 1648 | 1766 | if (lhs_val.floatHasFraction()) { |
| 1649 | 1767 | switch (op) { |
| 1650 | .eq => return self.constBool(src, false), | |
| 1651 | .neq => return self.constBool(src, true), | |
| 1768 | .eq => return self.constBool(scope, src, false), | |
| 1769 | .neq => return self.constBool(scope, src, true), | |
| 1652 | 1770 | else => {}, |
| 1653 | 1771 | } |
| 1654 | 1772 | if (zcmp == .lt) { |
| ... | ... | @@ -1682,8 +1800,8 @@ pub const Module = struct { |
| 1682 | 1800 | const zcmp = rhs_val.orderAgainstZero(); |
| 1683 | 1801 | if (rhs_val.floatHasFraction()) { |
| 1684 | 1802 | switch (op) { |
| 1685 | .eq => return self.constBool(src, false), | |
| 1686 | .neq => return self.constBool(src, true), | |
| 1803 | .eq => return self.constBool(scope, src, false), | |
| 1804 | .neq => return self.constBool(scope, src, true), | |
| 1687 | 1805 | else => {}, |
| 1688 | 1806 | } |
| 1689 | 1807 | if (zcmp == .lt) { |
| ... | ... | @@ -1711,7 +1829,7 @@ pub const Module = struct { |
| 1711 | 1829 | const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) { |
| 1712 | 1830 | error.Overflow => return self.fail(scope, src, "{} exceeds maximum integer bit count", .{max_bits}), |
| 1713 | 1831 | }; |
| 1714 | break :blk try self.makeIntType(dest_int_is_signed, casted_bits); | |
| 1832 | break :blk try self.makeIntType(scope, dest_int_is_signed, casted_bits); | |
| 1715 | 1833 | }; |
| 1716 | 1834 | const casted_lhs = try self.coerce(scope, dest_type, lhs); |
| 1717 | 1835 | const casted_rhs = try self.coerce(scope, dest_type, lhs); |
| ... | ... | @@ -1807,7 +1925,6 @@ pub const Module = struct { |
| 1807 | 1925 | fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError { |
| 1808 | 1926 | @setCold(true); |
| 1809 | 1927 | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 1810 | try self.failed_fns.ensureCapacity(self.failed_fns.size + 1); | |
| 1811 | 1928 | const err_msg = try ErrorMsg.create(self.allocator, src, format, args); |
| 1812 | 1929 | switch (scope.tag) { |
| 1813 | 1930 | .decl => { |
| ... | ... | @@ -1820,10 +1937,11 @@ pub const Module = struct { |
| 1820 | 1937 | self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg); |
| 1821 | 1938 | }, |
| 1822 | 1939 | .block => { |
| 1823 | const func = scope.cast(Scope.Block).?.func; | |
| 1824 | func.analysis = .failure; | |
| 1825 | self.failed_fns.putAssumeCapacityNoClobber(func, err_msg); | |
| 1940 | const block = scope.cast(Scope.Block).?; | |
| 1941 | block.func.analysis = .failure; | |
| 1942 | self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg); | |
| 1826 | 1943 | }, |
| 1944 | .zir_module => unreachable, | |
| 1827 | 1945 | } |
| 1828 | 1946 | return error.AnalysisFail; |
| 1829 | 1947 | } |
| ... | ... | @@ -1868,7 +1986,7 @@ pub const ErrorMsg = struct { |
| 1868 | 1986 | } |
| 1869 | 1987 | |
| 1870 | 1988 | pub fn deinit(self: *ErrorMsg, allocator: *Allocator) void { |
| 1871 | allocator.free(err_msg.msg); | |
| 1989 | allocator.free(self.msg); | |
| 1872 | 1990 | self.* = undefined; |
| 1873 | 1991 | } |
| 1874 | 1992 | }; |
| ... | ... | @@ -1920,7 +2038,6 @@ pub fn main() anyerror!void { |
| 1920 | 2038 | .decl_exports = std.AutoHashMap(*Module.Decl, []*Module.Export).init(allocator), |
| 1921 | 2039 | .export_owners = std.AutoHashMap(*Module.Decl, []*Module.Export).init(allocator), |
| 1922 | 2040 | .failed_decls = std.AutoHashMap(*Module.Decl, *ErrorMsg).init(allocator), |
| 1923 | .failed_fns = std.AutoHashMap(*Module.Fn, *ErrorMsg).init(allocator), | |
| 1924 | 2041 | .failed_files = std.AutoHashMap(*Module.Scope.ZIRModule, *ErrorMsg).init(allocator), |
| 1925 | 2042 | .failed_exports = std.AutoHashMap(*Module.Export, *ErrorMsg).init(allocator), |
| 1926 | 2043 | }; |
| ... | ... | @@ -1929,8 +2046,8 @@ pub fn main() anyerror!void { |
| 1929 | 2046 | |
| 1930 | 2047 | try module.update(); |
| 1931 | 2048 | |
| 1932 | const errors = try module.getAllErrorsAlloc(); | |
| 1933 | defer errors.deinit(); | |
| 2049 | var errors = try module.getAllErrorsAlloc(); | |
| 2050 | defer errors.deinit(allocator); | |
| 1934 | 2051 | |
| 1935 | 2052 | if (errors.list.len != 0) { |
| 1936 | 2053 | for (errors.list) |full_err_msg| { |
| ... | ... | @@ -1954,6 +2071,3 @@ pub fn main() anyerror!void { |
| 1954 | 2071 | try bos.flush(); |
| 1955 | 2072 | } |
| 1956 | 2073 | } |
| 1957 | ||
| 1958 | // Performance optimization ideas: | |
| 1959 | // * when analyzing use a field in the Inst instead of HashMap to track corresponding instructions |
src-self-hosted/ir/text.zig+139-47| ... | ... | @@ -8,6 +8,7 @@ const BigIntConst = std.math.big.int.Const; |
| 8 | 8 | const BigIntMutable = std.math.big.int.Mutable; |
| 9 | 9 | const Type = @import("../type.zig").Type; |
| 10 | 10 | const Value = @import("../value.zig").Value; |
| 11 | const TypedValue = @import("../TypedValue.zig"); | |
| 11 | 12 | const ir = @import("../ir.zig"); |
| 12 | 13 | |
| 13 | 14 | /// These are instructions that correspond to the ZIR text format. See `ir.Inst` for |
| ... | ... | @@ -462,6 +463,7 @@ pub const Module = struct { |
| 462 | 463 | switch (decl.tag) { |
| 463 | 464 | .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table), |
| 464 | 465 | .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table), |
| 466 | .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table), | |
| 465 | 467 | .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table), |
| 466 | 468 | .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table), |
| 467 | 469 | .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table), |
| ... | ... | @@ -576,6 +578,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module |
| 576 | 578 | .source = source, |
| 577 | 579 | .global_name_map = &global_name_map, |
| 578 | 580 | .decls = .{}, |
| 581 | .unnamed_index = 0, | |
| 579 | 582 | }; |
| 580 | 583 | errdefer parser.arena.deinit(); |
| 581 | 584 | |
| ... | ... | @@ -601,6 +604,7 @@ const Parser = struct { |
| 601 | 604 | decls: std.ArrayListUnmanaged(*Inst), |
| 602 | 605 | global_name_map: *std.StringHashMap(usize), |
| 603 | 606 | error_msg: ?ErrorMsg = null, |
| 607 | unnamed_index: usize, | |
| 604 | 608 | |
| 605 | 609 | const Body = struct { |
| 606 | 610 | instructions: std.ArrayList(*Inst), |
| ... | ... | @@ -626,12 +630,12 @@ const Parser = struct { |
| 626 | 630 | skipSpace(self); |
| 627 | 631 | try requireEatBytes(self, "="); |
| 628 | 632 | skipSpace(self); |
| 629 | const inst = try parseInstruction(self, &body_context); | |
| 633 | const inst = try parseInstruction(self, &body_context, ident[1..]); | |
| 630 | 634 | const ident_index = body_context.instructions.items.len; |
| 631 | 635 | if (try body_context.name_map.put(ident, ident_index)) |_| { |
| 632 | 636 | return self.fail("redefinition of identifier '{}'", .{ident}); |
| 633 | 637 | } |
| 634 | try body_context.instructions.append(self.allocator, inst); | |
| 638 | try body_context.instructions.append(inst); | |
| 635 | 639 | continue; |
| 636 | 640 | }, |
| 637 | 641 | ' ', '\n' => continue, |
| ... | ... | @@ -712,7 +716,7 @@ const Parser = struct { |
| 712 | 716 | skipSpace(self); |
| 713 | 717 | try requireEatBytes(self, "="); |
| 714 | 718 | skipSpace(self); |
| 715 | const inst = try parseInstruction(self, null); | |
| 719 | const inst = try parseInstruction(self, null, ident[1..]); | |
| 716 | 720 | const ident_index = self.decls.items.len; |
| 717 | 721 | if (try self.global_name_map.put(ident, ident_index)) |_| { |
| 718 | 722 | return self.fail("redefinition of identifier '{}'", .{ident}); |
| ... | ... | @@ -781,12 +785,12 @@ const Parser = struct { |
| 781 | 785 | return error.ParseFailure; |
| 782 | 786 | } |
| 783 | 787 | |
| 784 | fn parseInstruction(self: *Parser, body_ctx: ?*Body) InnerError!*Inst { | |
| 788 | fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Inst { | |
| 785 | 789 | const fn_name = try skipToAndOver(self, '('); |
| 786 | 790 | inline for (@typeInfo(Inst.Tag).Enum.fields) |field| { |
| 787 | 791 | if (mem.eql(u8, field.name, fn_name)) { |
| 788 | 792 | const tag = @field(Inst.Tag, field.name); |
| 789 | return parseInstructionGeneric(self, field.name, Inst.TagToType(tag), body_ctx); | |
| 793 | return parseInstructionGeneric(self, field.name, Inst.TagToType(tag), body_ctx, name); | |
| 790 | 794 | } |
| 791 | 795 | } |
| 792 | 796 | return self.fail("unknown instruction '{}'", .{fn_name}); |
| ... | ... | @@ -797,9 +801,11 @@ const Parser = struct { |
| 797 | 801 | comptime fn_name: []const u8, |
| 798 | 802 | comptime InstType: type, |
| 799 | 803 | body_ctx: ?*Body, |
| 800 | ) !*Inst { | |
| 804 | inst_name: []const u8, | |
| 805 | ) InnerError!*Inst { | |
| 801 | 806 | const inst_specific = try self.arena.allocator.create(InstType); |
| 802 | 807 | inst_specific.base = .{ |
| 808 | .name = inst_name, | |
| 803 | 809 | .src = self.i, |
| 804 | 810 | .tag = InstType.base_tag, |
| 805 | 811 | }; |
| ... | ... | @@ -885,7 +891,7 @@ const Parser = struct { |
| 885 | 891 | var instructions = std.ArrayList(*Inst).init(&self.arena.allocator); |
| 886 | 892 | while (true) { |
| 887 | 893 | skipSpace(self); |
| 888 | try instructions.append(self.allocator, try parseParameterInst(self, body_ctx)); | |
| 894 | try instructions.append(try parseParameterInst(self, body_ctx)); | |
| 889 | 895 | skipSpace(self); |
| 890 | 896 | if (!eatByte(self, ',')) break; |
| 891 | 897 | } |
| ... | ... | @@ -930,13 +936,21 @@ const Parser = struct { |
| 930 | 936 | } else { |
| 931 | 937 | const name = try self.arena.allocator.create(Inst.Str); |
| 932 | 938 | name.* = .{ |
| 933 | .base = .{ .src = src, .tag = Inst.Str.base_tag }, | |
| 939 | .base = .{ | |
| 940 | .name = try self.generateName(), | |
| 941 | .src = src, | |
| 942 | .tag = Inst.Str.base_tag, | |
| 943 | }, | |
| 934 | 944 | .positionals = .{ .bytes = ident }, |
| 935 | 945 | .kw_args = .{}, |
| 936 | 946 | }; |
| 937 | 947 | const declref = try self.arena.allocator.create(Inst.DeclRef); |
| 938 | 948 | declref.* = .{ |
| 939 | .base = .{ .src = src, .tag = Inst.DeclRef.base_tag }, | |
| 949 | .base = .{ | |
| 950 | .name = try self.generateName(), | |
| 951 | .src = src, | |
| 952 | .tag = Inst.DeclRef.base_tag, | |
| 953 | }, | |
| 940 | 954 | .positionals = .{ .name = &name.base }, |
| 941 | 955 | .kw_args = .{}, |
| 942 | 956 | }; |
| ... | ... | @@ -949,25 +963,31 @@ const Parser = struct { |
| 949 | 963 | return self.decls.items[kv.value]; |
| 950 | 964 | } |
| 951 | 965 | } |
| 966 | ||
| 967 | fn generateName(self: *Parser) ![]u8 { | |
| 968 | const result = try std.fmt.allocPrint(&self.arena.allocator, "unnamed${}", .{self.unnamed_index}); | |
| 969 | self.unnamed_index += 1; | |
| 970 | return result; | |
| 971 | } | |
| 952 | 972 | }; |
| 953 | 973 | |
| 954 | 974 | pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module { |
| 955 | 975 | var ctx: EmitZIR = .{ |
| 956 | 976 | .allocator = allocator, |
| 957 | .decls = std.ArrayList(*Inst).init(allocator), | |
| 977 | .decls = .{}, | |
| 958 | 978 | .decl_table = std.AutoHashMap(*ir.Inst, *Inst).init(allocator), |
| 959 | 979 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 960 | 980 | .old_module = &old_module, |
| 961 | 981 | }; |
| 962 | defer ctx.decls.deinit(); | |
| 982 | defer ctx.decls.deinit(allocator); | |
| 963 | 983 | defer ctx.decl_table.deinit(); |
| 964 | 984 | errdefer ctx.arena.deinit(); |
| 965 | 985 | |
| 966 | 986 | try ctx.emit(); |
| 967 | 987 | |
| 968 | 988 | return Module{ |
| 969 | .decls = ctx.decls.toOwnedSlice(), | |
| 970 | .arena = ctx.arena, | |
| 989 | .decls = ctx.decls.toOwnedSlice(allocator), | |
| 990 | .arena = ctx.arena.state, | |
| 971 | 991 | }; |
| 972 | 992 | } |
| 973 | 993 | |
| ... | ... | @@ -975,23 +995,32 @@ const EmitZIR = struct { |
| 975 | 995 | allocator: *Allocator, |
| 976 | 996 | arena: std.heap.ArenaAllocator, |
| 977 | 997 | old_module: *const ir.Module, |
| 978 | decls: std.ArrayList(*Inst), | |
| 998 | decls: std.ArrayListUnmanaged(*Inst), | |
| 979 | 999 | decl_table: std.AutoHashMap(*ir.Inst, *Inst), |
| 980 | 1000 | |
| 981 | 1001 | fn emit(self: *EmitZIR) !void { |
| 982 | for (self.old_module.exports) |module_export| { | |
| 983 | const export_value = try self.emitTypedValue(module_export.src, module_export.typed_value); | |
| 984 | const symbol_name = try self.emitStringLiteral(module_export.src, module_export.name); | |
| 985 | const export_inst = try self.arena.allocator.create(Inst.Export); | |
| 986 | export_inst.* = .{ | |
| 987 | .base = .{ .src = module_export.src, .tag = Inst.Export.base_tag }, | |
| 988 | .positionals = .{ | |
| 989 | .symbol_name = symbol_name, | |
| 990 | .value = export_value, | |
| 991 | }, | |
| 992 | .kw_args = .{}, | |
| 993 | }; | |
| 994 | try self.decls.append(self.allocator, &export_inst.base); | |
| 1002 | var it = self.old_module.decl_exports.iterator(); | |
| 1003 | while (it.next()) |kv| { | |
| 1004 | const decl = kv.key; | |
| 1005 | const exports = kv.value; | |
| 1006 | const export_value = try self.emitTypedValue(decl.src, decl.typed_value.most_recent.typed_value); | |
| 1007 | for (exports) |module_export| { | |
| 1008 | const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name); | |
| 1009 | const export_inst = try self.arena.allocator.create(Inst.Export); | |
| 1010 | export_inst.* = .{ | |
| 1011 | .base = .{ | |
| 1012 | .name = try self.autoName(), | |
| 1013 | .src = module_export.src, | |
| 1014 | .tag = Inst.Export.base_tag, | |
| 1015 | }, | |
| 1016 | .positionals = .{ | |
| 1017 | .symbol_name = symbol_name, | |
| 1018 | .value = export_value, | |
| 1019 | }, | |
| 1020 | .kw_args = .{}, | |
| 1021 | }; | |
| 1022 | try self.decls.append(self.allocator, &export_inst.base); | |
| 1023 | } | |
| 995 | 1024 | } |
| 996 | 1025 | } |
| 997 | 1026 | |
| ... | ... | @@ -1012,7 +1041,11 @@ const EmitZIR = struct { |
| 1012 | 1041 | const big_int_space = try self.arena.allocator.create(Value.BigIntSpace); |
| 1013 | 1042 | const int_inst = try self.arena.allocator.create(Inst.Int); |
| 1014 | 1043 | int_inst.* = .{ |
| 1015 | .base = .{ .src = src, .tag = Inst.Int.base_tag }, | |
| 1044 | .base = .{ | |
| 1045 | .name = try self.autoName(), | |
| 1046 | .src = src, | |
| 1047 | .tag = Inst.Int.base_tag, | |
| 1048 | }, | |
| 1016 | 1049 | .positionals = .{ |
| 1017 | 1050 | .int = val.toBigInt(big_int_space), |
| 1018 | 1051 | }, |
| ... | ... | @@ -1022,7 +1055,7 @@ const EmitZIR = struct { |
| 1022 | 1055 | return &int_inst.base; |
| 1023 | 1056 | } |
| 1024 | 1057 | |
| 1025 | fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: ir.TypedValue) Allocator.Error!*Inst { | |
| 1058 | fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst { | |
| 1026 | 1059 | switch (typed_value.ty.zigTypeTag()) { |
| 1027 | 1060 | .Pointer => { |
| 1028 | 1061 | const ptr_elem_type = typed_value.ty.elemType(); |
| ... | ... | @@ -1044,7 +1077,11 @@ const EmitZIR = struct { |
| 1044 | 1077 | .Int => { |
| 1045 | 1078 | const as_inst = try self.arena.allocator.create(Inst.As); |
| 1046 | 1079 | as_inst.* = .{ |
| 1047 | .base = .{ .src = src, .tag = Inst.As.base_tag }, | |
| 1080 | .base = .{ | |
| 1081 | .name = try self.autoName(), | |
| 1082 | .src = src, | |
| 1083 | .tag = Inst.As.base_tag, | |
| 1084 | }, | |
| 1048 | 1085 | .positionals = .{ |
| 1049 | 1086 | .dest_type = try self.emitType(src, typed_value.ty), |
| 1050 | 1087 | .value = try self.emitComptimeIntVal(src, typed_value.val), |
| ... | ... | @@ -1060,8 +1097,7 @@ const EmitZIR = struct { |
| 1060 | 1097 | return self.emitType(src, ty); |
| 1061 | 1098 | }, |
| 1062 | 1099 | .Fn => { |
| 1063 | const index = typed_value.val.cast(Value.Payload.Function).?.index; | |
| 1064 | const module_fn = self.old_module.fns[index]; | |
| 1100 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; | |
| 1065 | 1101 | |
| 1066 | 1102 | var inst_table = std.AutoHashMap(*ir.Inst, *Inst).init(self.allocator); |
| 1067 | 1103 | defer inst_table.deinit(); |
| ... | ... | @@ -1069,7 +1105,7 @@ const EmitZIR = struct { |
| 1069 | 1105 | var instructions = std.ArrayList(*Inst).init(self.allocator); |
| 1070 | 1106 | defer instructions.deinit(); |
| 1071 | 1107 | |
| 1072 | try self.emitBody(module_fn.body, &inst_table, &instructions); | |
| 1108 | try self.emitBody(module_fn.analysis.success, &inst_table, &instructions); | |
| 1073 | 1109 | |
| 1074 | 1110 | const fn_type = try self.emitType(src, module_fn.fn_type); |
| 1075 | 1111 | |
| ... | ... | @@ -1078,7 +1114,11 @@ const EmitZIR = struct { |
| 1078 | 1114 | |
| 1079 | 1115 | const fn_inst = try self.arena.allocator.create(Inst.Fn); |
| 1080 | 1116 | fn_inst.* = .{ |
| 1081 | .base = .{ .src = src, .tag = Inst.Fn.base_tag }, | |
| 1117 | .base = .{ | |
| 1118 | .name = try self.autoName(), | |
| 1119 | .src = src, | |
| 1120 | .tag = Inst.Fn.base_tag, | |
| 1121 | }, | |
| 1082 | 1122 | .positionals = .{ |
| 1083 | 1123 | .fn_type = fn_type, |
| 1084 | 1124 | .body = .{ .instructions = arena_instrs }, |
| ... | ... | @@ -1095,7 +1135,11 @@ const EmitZIR = struct { |
| 1095 | 1135 | fn emitTrivial(self: *EmitZIR, src: usize, comptime T: type) Allocator.Error!*Inst { |
| 1096 | 1136 | const new_inst = try self.arena.allocator.create(T); |
| 1097 | 1137 | new_inst.* = .{ |
| 1098 | .base = .{ .src = src, .tag = T.base_tag }, | |
| 1138 | .base = .{ | |
| 1139 | .name = try self.autoName(), | |
| 1140 | .src = src, | |
| 1141 | .tag = T.base_tag, | |
| 1142 | }, | |
| 1099 | 1143 | .positionals = .{}, |
| 1100 | 1144 | .kw_args = .{}, |
| 1101 | 1145 | }; |
| ... | ... | @@ -1120,7 +1164,11 @@ const EmitZIR = struct { |
| 1120 | 1164 | elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]); |
| 1121 | 1165 | } |
| 1122 | 1166 | new_inst.* = .{ |
| 1123 | .base = .{ .src = inst.src, .tag = Inst.Call.base_tag }, | |
| 1167 | .base = .{ | |
| 1168 | .name = try self.autoName(), | |
| 1169 | .src = inst.src, | |
| 1170 | .tag = Inst.Call.base_tag, | |
| 1171 | }, | |
| 1124 | 1172 | .positionals = .{ |
| 1125 | 1173 | .func = try self.resolveInst(inst_table, old_inst.args.func), |
| 1126 | 1174 | .args = args, |
| ... | ... | @@ -1152,7 +1200,11 @@ const EmitZIR = struct { |
| 1152 | 1200 | } |
| 1153 | 1201 | |
| 1154 | 1202 | new_inst.* = .{ |
| 1155 | .base = .{ .src = inst.src, .tag = Inst.Asm.base_tag }, | |
| 1203 | .base = .{ | |
| 1204 | .name = try self.autoName(), | |
| 1205 | .src = inst.src, | |
| 1206 | .tag = Inst.Asm.base_tag, | |
| 1207 | }, | |
| 1156 | 1208 | .positionals = .{ |
| 1157 | 1209 | .asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source), |
| 1158 | 1210 | .return_type = try self.emitType(inst.src, inst.ty), |
| ... | ... | @@ -1174,7 +1226,11 @@ const EmitZIR = struct { |
| 1174 | 1226 | const old_inst = inst.cast(ir.Inst.PtrToInt).?; |
| 1175 | 1227 | const new_inst = try self.arena.allocator.create(Inst.PtrToInt); |
| 1176 | 1228 | new_inst.* = .{ |
| 1177 | .base = .{ .src = inst.src, .tag = Inst.PtrToInt.base_tag }, | |
| 1229 | .base = .{ | |
| 1230 | .name = try self.autoName(), | |
| 1231 | .src = inst.src, | |
| 1232 | .tag = Inst.PtrToInt.base_tag, | |
| 1233 | }, | |
| 1178 | 1234 | .positionals = .{ |
| 1179 | 1235 | .ptr = try self.resolveInst(inst_table, old_inst.args.ptr), |
| 1180 | 1236 | }, |
| ... | ... | @@ -1186,7 +1242,11 @@ const EmitZIR = struct { |
| 1186 | 1242 | const old_inst = inst.cast(ir.Inst.BitCast).?; |
| 1187 | 1243 | const new_inst = try self.arena.allocator.create(Inst.BitCast); |
| 1188 | 1244 | new_inst.* = .{ |
| 1189 | .base = .{ .src = inst.src, .tag = Inst.BitCast.base_tag }, | |
| 1245 | .base = .{ | |
| 1246 | .name = try self.autoName(), | |
| 1247 | .src = inst.src, | |
| 1248 | .tag = Inst.BitCast.base_tag, | |
| 1249 | }, | |
| 1190 | 1250 | .positionals = .{ |
| 1191 | 1251 | .dest_type = try self.emitType(inst.src, inst.ty), |
| 1192 | 1252 | .operand = try self.resolveInst(inst_table, old_inst.args.operand), |
| ... | ... | @@ -1199,7 +1259,11 @@ const EmitZIR = struct { |
| 1199 | 1259 | const old_inst = inst.cast(ir.Inst.Cmp).?; |
| 1200 | 1260 | const new_inst = try self.arena.allocator.create(Inst.Cmp); |
| 1201 | 1261 | new_inst.* = .{ |
| 1202 | .base = .{ .src = inst.src, .tag = Inst.Cmp.base_tag }, | |
| 1262 | .base = .{ | |
| 1263 | .name = try self.autoName(), | |
| 1264 | .src = inst.src, | |
| 1265 | .tag = Inst.Cmp.base_tag, | |
| 1266 | }, | |
| 1203 | 1267 | .positionals = .{ |
| 1204 | 1268 | .lhs = try self.resolveInst(inst_table, old_inst.args.lhs), |
| 1205 | 1269 | .rhs = try self.resolveInst(inst_table, old_inst.args.rhs), |
| ... | ... | @@ -1223,7 +1287,11 @@ const EmitZIR = struct { |
| 1223 | 1287 | |
| 1224 | 1288 | const new_inst = try self.arena.allocator.create(Inst.CondBr); |
| 1225 | 1289 | new_inst.* = .{ |
| 1226 | .base = .{ .src = inst.src, .tag = Inst.CondBr.base_tag }, | |
| 1290 | .base = .{ | |
| 1291 | .name = try self.autoName(), | |
| 1292 | .src = inst.src, | |
| 1293 | .tag = Inst.CondBr.base_tag, | |
| 1294 | }, | |
| 1227 | 1295 | .positionals = .{ |
| 1228 | 1296 | .condition = try self.resolveInst(inst_table, old_inst.args.condition), |
| 1229 | 1297 | .true_body = .{ .instructions = true_body.toOwnedSlice() }, |
| ... | ... | @@ -1237,7 +1305,11 @@ const EmitZIR = struct { |
| 1237 | 1305 | const old_inst = inst.cast(ir.Inst.IsNull).?; |
| 1238 | 1306 | const new_inst = try self.arena.allocator.create(Inst.IsNull); |
| 1239 | 1307 | new_inst.* = .{ |
| 1240 | .base = .{ .src = inst.src, .tag = Inst.IsNull.base_tag }, | |
| 1308 | .base = .{ | |
| 1309 | .name = try self.autoName(), | |
| 1310 | .src = inst.src, | |
| 1311 | .tag = Inst.IsNull.base_tag, | |
| 1312 | }, | |
| 1241 | 1313 | .positionals = .{ |
| 1242 | 1314 | .operand = try self.resolveInst(inst_table, old_inst.args.operand), |
| 1243 | 1315 | }, |
| ... | ... | @@ -1249,7 +1321,11 @@ const EmitZIR = struct { |
| 1249 | 1321 | const old_inst = inst.cast(ir.Inst.IsNonNull).?; |
| 1250 | 1322 | const new_inst = try self.arena.allocator.create(Inst.IsNonNull); |
| 1251 | 1323 | new_inst.* = .{ |
| 1252 | .base = .{ .src = inst.src, .tag = Inst.IsNonNull.base_tag }, | |
| 1324 | .base = .{ | |
| 1325 | .name = try self.autoName(), | |
| 1326 | .src = inst.src, | |
| 1327 | .tag = Inst.IsNonNull.base_tag, | |
| 1328 | }, | |
| 1253 | 1329 | .positionals = .{ |
| 1254 | 1330 | .operand = try self.resolveInst(inst_table, old_inst.args.operand), |
| 1255 | 1331 | }, |
| ... | ... | @@ -1258,7 +1334,7 @@ const EmitZIR = struct { |
| 1258 | 1334 | break :blk &new_inst.base; |
| 1259 | 1335 | }, |
| 1260 | 1336 | }; |
| 1261 | try instructions.append(self.allocator, new_inst); | |
| 1337 | try instructions.append(new_inst); | |
| 1262 | 1338 | try inst_table.putNoClobber(inst, new_inst); |
| 1263 | 1339 | } |
| 1264 | 1340 | } |
| ... | ... | @@ -1301,7 +1377,11 @@ const EmitZIR = struct { |
| 1301 | 1377 | |
| 1302 | 1378 | const fntype_inst = try self.arena.allocator.create(Inst.FnType); |
| 1303 | 1379 | fntype_inst.* = .{ |
| 1304 | .base = .{ .src = src, .tag = Inst.FnType.base_tag }, | |
| 1380 | .base = .{ | |
| 1381 | .name = try self.autoName(), | |
| 1382 | .src = src, | |
| 1383 | .tag = Inst.FnType.base_tag, | |
| 1384 | }, | |
| 1305 | 1385 | .positionals = .{ |
| 1306 | 1386 | .param_types = emitted_params, |
| 1307 | 1387 | .return_type = try self.emitType(src, ty.fnReturnType()), |
| ... | ... | @@ -1318,10 +1398,18 @@ const EmitZIR = struct { |
| 1318 | 1398 | } |
| 1319 | 1399 | } |
| 1320 | 1400 | |
| 1401 | fn autoName(self: *EmitZIR) ![]u8 { | |
| 1402 | return std.fmt.allocPrint(&self.arena.allocator, "{}", .{self.decls.items.len}); | |
| 1403 | } | |
| 1404 | ||
| 1321 | 1405 | fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst { |
| 1322 | 1406 | const primitive_inst = try self.arena.allocator.create(Inst.Primitive); |
| 1323 | 1407 | primitive_inst.* = .{ |
| 1324 | .base = .{ .src = src, .tag = Inst.Primitive.base_tag }, | |
| 1408 | .base = .{ | |
| 1409 | .name = try self.autoName(), | |
| 1410 | .src = src, | |
| 1411 | .tag = Inst.Primitive.base_tag, | |
| 1412 | }, | |
| 1325 | 1413 | .positionals = .{ |
| 1326 | 1414 | .tag = tag, |
| 1327 | 1415 | }, |
| ... | ... | @@ -1334,7 +1422,11 @@ const EmitZIR = struct { |
| 1334 | 1422 | fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst { |
| 1335 | 1423 | const str_inst = try self.arena.allocator.create(Inst.Str); |
| 1336 | 1424 | str_inst.* = .{ |
| 1337 | .base = .{ .src = src, .tag = Inst.Str.base_tag }, | |
| 1425 | .base = .{ | |
| 1426 | .name = try self.autoName(), | |
| 1427 | .src = src, | |
| 1428 | .tag = Inst.Str.base_tag, | |
| 1429 | }, | |
| 1338 | 1430 | .positionals = .{ |
| 1339 | 1431 | .bytes = str, |
| 1340 | 1432 | }, |
src-self-hosted/link.zig+61-29| ... | ... | @@ -153,7 +153,7 @@ pub const ElfFile = struct { |
| 153 | 153 | }; |
| 154 | 154 | |
| 155 | 155 | pub const Export = struct { |
| 156 | sym_index: usize, | |
| 156 | sym_index: ?usize = null, | |
| 157 | 157 | }; |
| 158 | 158 | |
| 159 | 159 | pub fn deinit(self: *ElfFile) void { |
| ... | ... | @@ -249,6 +249,11 @@ pub const ElfFile = struct { |
| 249 | 249 | return @intCast(u32, result); |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | fn getString(self: *ElfFile, str_off: u32) []const u8 { | |
| 253 | assert(str_off < self.shstrtab.items.len); | |
| 254 | return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); | |
| 255 | } | |
| 256 | ||
| 252 | 257 | fn updateString(self: *ElfFile, old_str_off: u32, new_name: []const u8) !u32 { |
| 253 | 258 | const existing_name = self.getString(old_str_off); |
| 254 | 259 | if (mem.eql(u8, existing_name, new_name)) { |
| ... | ... | @@ -418,6 +423,14 @@ pub const ElfFile = struct { |
| 418 | 423 | const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 419 | 424 | |
| 420 | 425 | if (self.phdr_table_dirty) { |
| 426 | const phsize: u64 = switch (self.ptr_width) { | |
| 427 | .p32 => @sizeOf(elf.Elf32_Phdr), | |
| 428 | .p64 => @sizeOf(elf.Elf64_Phdr), | |
| 429 | }; | |
| 430 | const phalign: u16 = switch (self.ptr_width) { | |
| 431 | .p32 => @alignOf(elf.Elf32_Phdr), | |
| 432 | .p64 => @alignOf(elf.Elf64_Phdr), | |
| 433 | }; | |
| 421 | 434 | const allocated_size = self.allocatedSize(self.phdr_table_offset.?); |
| 422 | 435 | const needed_size = self.program_headers.items.len * phsize; |
| 423 | 436 | |
| ... | ... | @@ -426,11 +439,10 @@ pub const ElfFile = struct { |
| 426 | 439 | self.phdr_table_offset = self.findFreeSpace(needed_size, phalign); |
| 427 | 440 | } |
| 428 | 441 | |
| 429 | const allocator = self.program_headers.allocator; | |
| 430 | 442 | switch (self.ptr_width) { |
| 431 | 443 | .p32 => { |
| 432 | const buf = try allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); | |
| 433 | defer allocator.free(buf); | |
| 444 | const buf = try self.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len); | |
| 445 | defer self.allocator.free(buf); | |
| 434 | 446 | |
| 435 | 447 | for (buf) |*phdr, i| { |
| 436 | 448 | phdr.* = progHeaderTo32(self.program_headers.items[i]); |
| ... | ... | @@ -441,8 +453,8 @@ pub const ElfFile = struct { |
| 441 | 453 | try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?); |
| 442 | 454 | }, |
| 443 | 455 | .p64 => { |
| 444 | const buf = try allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); | |
| 445 | defer allocator.free(buf); | |
| 456 | const buf = try self.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len); | |
| 457 | defer self.allocator.free(buf); | |
| 446 | 458 | |
| 447 | 459 | for (buf) |*phdr, i| { |
| 448 | 460 | phdr.* = self.program_headers.items[i]; |
| ... | ... | @@ -478,12 +490,20 @@ pub const ElfFile = struct { |
| 478 | 490 | } |
| 479 | 491 | } |
| 480 | 492 | if (self.shdr_table_dirty) { |
| 493 | const shsize: u64 = switch (self.ptr_width) { | |
| 494 | .p32 => @sizeOf(elf.Elf32_Shdr), | |
| 495 | .p64 => @sizeOf(elf.Elf64_Shdr), | |
| 496 | }; | |
| 497 | const shalign: u16 = switch (self.ptr_width) { | |
| 498 | .p32 => @alignOf(elf.Elf32_Shdr), | |
| 499 | .p64 => @alignOf(elf.Elf64_Shdr), | |
| 500 | }; | |
| 481 | 501 | const allocated_size = self.allocatedSize(self.shdr_table_offset.?); |
| 482 | const needed_size = self.sections.items.len * phsize; | |
| 502 | const needed_size = self.sections.items.len * shsize; | |
| 483 | 503 | |
| 484 | 504 | if (needed_size > allocated_size) { |
| 485 | 505 | self.shdr_table_offset = null; // free the space |
| 486 | self.shdr_table_offset = self.findFreeSpace(needed_size, phalign); | |
| 506 | self.shdr_table_offset = self.findFreeSpace(needed_size, shalign); | |
| 487 | 507 | } |
| 488 | 508 | |
| 489 | 509 | switch (self.ptr_width) { |
| ... | ... | @@ -719,7 +739,7 @@ pub const ElfFile = struct { |
| 719 | 739 | defer code.deinit(); |
| 720 | 740 | |
| 721 | 741 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 722 | const err_msg = try codegen.generateSymbol(typed_value, module, &code); | |
| 742 | const err_msg = try codegen.generateSymbol(typed_value, module.*, &code); | |
| 723 | 743 | if (err_msg != null) |em| { |
| 724 | 744 | decl.analysis = .codegen_failure; |
| 725 | 745 | _ = try module.failed_decls.put(decl, em); |
| ... | ... | @@ -751,15 +771,15 @@ pub const ElfFile = struct { |
| 751 | 771 | try self.writeSymbol(decl.link.local_sym_index); |
| 752 | 772 | break :blk file_offset; |
| 753 | 773 | } else { |
| 754 | try self.symbols.ensureCapacity(self.symbols.items.len + 1); | |
| 755 | try self.offset_table.ensureCapacity(self.offset_table.items.len + 1); | |
| 774 | try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + 1); | |
| 775 | try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1); | |
| 756 | 776 | const decl_name = mem.spanZ(u8, decl.name); |
| 757 | 777 | const name_str_index = try self.makeString(decl_name); |
| 758 | 778 | const new_block = try self.allocateTextBlock(code_size); |
| 759 | 779 | const local_sym_index = self.symbols.items.len; |
| 760 | 780 | const offset_table_index = self.offset_table.items.len; |
| 761 | 781 | |
| 762 | self.symbols.appendAssumeCapacity(self.allocator, .{ | |
| 782 | self.symbols.appendAssumeCapacity(.{ | |
| 763 | 783 | .st_name = name_str_index, |
| 764 | 784 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, |
| 765 | 785 | .st_other = 0, |
| ... | ... | @@ -767,9 +787,9 @@ pub const ElfFile = struct { |
| 767 | 787 | .st_value = new_block.vaddr, |
| 768 | 788 | .st_size = code_size, |
| 769 | 789 | }); |
| 770 | errdefer self.symbols.shrink(self.symbols.items.len - 1); | |
| 771 | self.offset_table.appendAssumeCapacity(self.allocator, new_block.vaddr); | |
| 772 | errdefer self.offset_table.shrink(self.offset_table.items.len - 1); | |
| 790 | errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1); | |
| 791 | self.offset_table.appendAssumeCapacity(new_block.vaddr); | |
| 792 | errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1); | |
| 773 | 793 | try self.writeSymbol(local_sym_index); |
| 774 | 794 | try self.writeOffsetTableEntry(offset_table_index); |
| 775 | 795 | |
| ... | ... | @@ -796,11 +816,12 @@ pub const ElfFile = struct { |
| 796 | 816 | self: *ElfFile, |
| 797 | 817 | module: *ir.Module, |
| 798 | 818 | decl: *const ir.Module.Decl, |
| 799 | exports: []const *const Export, | |
| 819 | exports: []const *ir.Module.Export, | |
| 800 | 820 | ) !void { |
| 801 | try self.symbols.ensureCapacity(self.symbols.items.len + exports.len); | |
| 821 | try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len); | |
| 802 | 822 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 803 | const decl_sym = self.symbols.items[decl.link.local_sym_index.?]; | |
| 823 | assert(decl.link.local_sym_index != 0); | |
| 824 | const decl_sym = self.symbols.items[decl.link.local_sym_index]; | |
| 804 | 825 | |
| 805 | 826 | for (exports) |exp| { |
| 806 | 827 | if (exp.options.section) |section_name| { |
| ... | ... | @@ -808,15 +829,16 @@ pub const ElfFile = struct { |
| 808 | 829 | try module.failed_exports.ensureCapacity(module.failed_exports.size + 1); |
| 809 | 830 | module.failed_exports.putAssumeCapacityNoClobber( |
| 810 | 831 | exp, |
| 811 | try ir.ErrorMsg.create(0, "Unimplemented: ExportOptions.section", .{}), | |
| 832 | try ir.ErrorMsg.create(self.allocator, 0, "Unimplemented: ExportOptions.section", .{}), | |
| 812 | 833 | ); |
| 834 | continue; | |
| 813 | 835 | } |
| 814 | 836 | } |
| 815 | const stb_bits = switch (exp.options.linkage) { | |
| 837 | const stb_bits: u8 = switch (exp.options.linkage) { | |
| 816 | 838 | .Internal => elf.STB_LOCAL, |
| 817 | 839 | .Strong => blk: { |
| 818 | 840 | if (mem.eql(u8, exp.options.name, "_start")) { |
| 819 | self.entry_addr = decl_symbol.vaddr; | |
| 841 | self.entry_addr = decl_sym.st_value; | |
| 820 | 842 | } |
| 821 | 843 | break :blk elf.STB_GLOBAL; |
| 822 | 844 | }, |
| ... | ... | @@ -825,8 +847,9 @@ pub const ElfFile = struct { |
| 825 | 847 | try module.failed_exports.ensureCapacity(module.failed_exports.size + 1); |
| 826 | 848 | module.failed_exports.putAssumeCapacityNoClobber( |
| 827 | 849 | exp, |
| 828 | try ir.ErrorMsg.create(0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), | |
| 850 | try ir.ErrorMsg.create(self.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), | |
| 829 | 851 | ); |
| 852 | continue; | |
| 830 | 853 | }, |
| 831 | 854 | }; |
| 832 | 855 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); |
| ... | ... | @@ -844,15 +867,15 @@ pub const ElfFile = struct { |
| 844 | 867 | } else { |
| 845 | 868 | const name = try self.makeString(exp.options.name); |
| 846 | 869 | const i = self.symbols.items.len; |
| 847 | self.symbols.appendAssumeCapacity(self.allocator, .{ | |
| 848 | .st_name = sn.name, | |
| 870 | self.symbols.appendAssumeCapacity(.{ | |
| 871 | .st_name = name, | |
| 849 | 872 | .st_info = (stb_bits << 4) | stt_bits, |
| 850 | 873 | .st_other = 0, |
| 851 | 874 | .st_shndx = self.text_section_index.?, |
| 852 | 875 | .st_value = decl_sym.st_value, |
| 853 | 876 | .st_size = decl_sym.st_size, |
| 854 | 877 | }); |
| 855 | errdefer self.symbols.shrink(self.symbols.items.len - 1); | |
| 878 | errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1); | |
| 856 | 879 | try self.writeSymbol(i); |
| 857 | 880 | |
| 858 | 881 | self.symbol_count_dirty = true; |
| ... | ... | @@ -946,10 +969,15 @@ pub const ElfFile = struct { |
| 946 | 969 | } |
| 947 | 970 | |
| 948 | 971 | fn writeSymbol(self: *ElfFile, index: usize) !void { |
| 972 | assert(index != 0); | |
| 949 | 973 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 950 | 974 | // Make sure we are not pointlessly writing symbol data that will have to get relocated |
| 951 | 975 | // due to running out of space. |
| 952 | 976 | if (self.symbol_count_dirty) { |
| 977 | const sym_size: u64 = switch (self.ptr_width) { | |
| 978 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 979 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 980 | }; | |
| 953 | 981 | const allocated_size = self.allocatedSize(syms_sect.sh_offset); |
| 954 | 982 | const needed_size = self.symbols.items.len * sym_size; |
| 955 | 983 | if (needed_size > allocated_size) { |
| ... | ... | @@ -990,11 +1018,15 @@ pub const ElfFile = struct { |
| 990 | 1018 | } |
| 991 | 1019 | |
| 992 | 1020 | fn writeAllSymbols(self: *ElfFile) !void { |
| 993 | const small_ptr = self.ptr_width == .p32; | |
| 994 | 1021 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 995 | const sym_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | |
| 996 | const sym_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | |
| 997 | ||
| 1022 | const sym_align: u16 = switch (self.ptr_width) { | |
| 1023 | .p32 => @alignOf(elf.Elf32_Sym), | |
| 1024 | .p64 => @alignOf(elf.Elf64_Sym), | |
| 1025 | }; | |
| 1026 | const sym_size: u64 = switch (self.ptr_width) { | |
| 1027 | .p32 => @sizeOf(elf.Elf32_Sym), | |
| 1028 | .p64 => @sizeOf(elf.Elf64_Sym), | |
| 1029 | }; | |
| 998 | 1030 | const allocated_size = self.allocatedSize(syms_sect.sh_offset); |
| 999 | 1031 | const needed_size = self.symbols.items.len * sym_size; |
| 1000 | 1032 | if (needed_size > allocated_size) { |
src-self-hosted/value.zig+30-11| ... | ... | @@ -67,6 +67,7 @@ pub const Value = extern union { |
| 67 | 67 | int_big_positive, |
| 68 | 68 | int_big_negative, |
| 69 | 69 | function, |
| 70 | ref_val, | |
| 70 | 71 | decl_ref, |
| 71 | 72 | elem_ptr, |
| 72 | 73 | bytes, |
| ... | ... | @@ -158,6 +159,11 @@ pub const Value = extern union { |
| 158 | 159 | .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), |
| 159 | 160 | .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), |
| 160 | 161 | .function => return out_stream.writeAll("(function)"), |
| 162 | .ref_val => { | |
| 163 | const ref_val = val.cast(Payload.RefVal).?; | |
| 164 | try out_stream.writeAll("&const "); | |
| 165 | val = ref_val.val; | |
| 166 | }, | |
| 161 | 167 | .decl_ref => return out_stream.writeAll("(decl ref)"), |
| 162 | 168 | .elem_ptr => { |
| 163 | 169 | const elem_ptr = val.cast(Payload.ElemPtr).?; |
| ... | ... | @@ -229,6 +235,7 @@ pub const Value = extern union { |
| 229 | 235 | .int_big_positive, |
| 230 | 236 | .int_big_negative, |
| 231 | 237 | .function, |
| 238 | .ref_val, | |
| 232 | 239 | .decl_ref, |
| 233 | 240 | .elem_ptr, |
| 234 | 241 | .bytes, |
| ... | ... | @@ -276,6 +283,7 @@ pub const Value = extern union { |
| 276 | 283 | .bool_false, |
| 277 | 284 | .null_value, |
| 278 | 285 | .function, |
| 286 | .ref_val, | |
| 279 | 287 | .decl_ref, |
| 280 | 288 | .elem_ptr, |
| 281 | 289 | .bytes, |
| ... | ... | @@ -333,6 +341,7 @@ pub const Value = extern union { |
| 333 | 341 | .bool_false, |
| 334 | 342 | .null_value, |
| 335 | 343 | .function, |
| 344 | .ref_val, | |
| 336 | 345 | .decl_ref, |
| 337 | 346 | .elem_ptr, |
| 338 | 347 | .bytes, |
| ... | ... | @@ -391,6 +400,7 @@ pub const Value = extern union { |
| 391 | 400 | .bool_false, |
| 392 | 401 | .null_value, |
| 393 | 402 | .function, |
| 403 | .ref_val, | |
| 394 | 404 | .decl_ref, |
| 395 | 405 | .elem_ptr, |
| 396 | 406 | .bytes, |
| ... | ... | @@ -454,6 +464,7 @@ pub const Value = extern union { |
| 454 | 464 | .bool_false, |
| 455 | 465 | .null_value, |
| 456 | 466 | .function, |
| 467 | .ref_val, | |
| 457 | 468 | .decl_ref, |
| 458 | 469 | .elem_ptr, |
| 459 | 470 | .bytes, |
| ... | ... | @@ -546,6 +557,7 @@ pub const Value = extern union { |
| 546 | 557 | .bool_false, |
| 547 | 558 | .null_value, |
| 548 | 559 | .function, |
| 560 | .ref_val, | |
| 549 | 561 | .decl_ref, |
| 550 | 562 | .elem_ptr, |
| 551 | 563 | .bytes, |
| ... | ... | @@ -600,6 +612,7 @@ pub const Value = extern union { |
| 600 | 612 | .bool_false, |
| 601 | 613 | .null_value, |
| 602 | 614 | .function, |
| 615 | .ref_val, | |
| 603 | 616 | .decl_ref, |
| 604 | 617 | .elem_ptr, |
| 605 | 618 | .bytes, |
| ... | ... | @@ -655,7 +668,8 @@ pub const Value = extern union { |
| 655 | 668 | } |
| 656 | 669 | |
| 657 | 670 | /// Asserts the value is a pointer and dereferences it. |
| 658 | pub fn pointerDeref(self: Value, module: *ir.Module) !Value { | |
| 671 | /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis. | |
| 672 | pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value { | |
| 659 | 673 | return switch (self.tag()) { |
| 660 | 674 | .ty, |
| 661 | 675 | .u8_type, |
| ... | ... | @@ -704,21 +718,19 @@ pub const Value = extern union { |
| 704 | 718 | => unreachable, |
| 705 | 719 | |
| 706 | 720 | .the_one_possible_value => Value.initTag(.the_one_possible_value), |
| 707 | .decl_ref => { | |
| 708 | const index = self.cast(Payload.DeclRef).?.index; | |
| 709 | return module.getDeclValue(index); | |
| 710 | }, | |
| 721 | .ref_val => self.cast(Payload.RefVal).?.val, | |
| 722 | .decl_ref => self.cast(Payload.DeclRef).?.decl.value(), | |
| 711 | 723 | .elem_ptr => { |
| 712 | const elem_ptr = self.cast(ElemPtr).?; | |
| 713 | const array_val = try elem_ptr.array_ptr.pointerDeref(module); | |
| 714 | return self.elemValue(array_val, elem_ptr.index); | |
| 724 | const elem_ptr = self.cast(Payload.ElemPtr).?; | |
| 725 | const array_val = try elem_ptr.array_ptr.pointerDeref(allocator); | |
| 726 | return array_val.elemValue(allocator, elem_ptr.index); | |
| 715 | 727 | }, |
| 716 | 728 | }; |
| 717 | 729 | } |
| 718 | 730 | |
| 719 | 731 | /// Asserts the value is a single-item pointer to an array, or an array, |
| 720 | 732 | /// or an unknown-length pointer, and returns the element value at the index. |
| 721 | pub fn elemValue(self: Value, index: usize) Value { | |
| 733 | pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value { | |
| 722 | 734 | switch (self.tag()) { |
| 723 | 735 | .ty, |
| 724 | 736 | .u8_type, |
| ... | ... | @@ -764,6 +776,7 @@ pub const Value = extern union { |
| 764 | 776 | .int_big_negative, |
| 765 | 777 | .undef, |
| 766 | 778 | .elem_ptr, |
| 779 | .ref_val, | |
| 767 | 780 | .decl_ref, |
| 768 | 781 | => unreachable, |
| 769 | 782 | |
| ... | ... | @@ -838,6 +851,7 @@ pub const Value = extern union { |
| 838 | 851 | .int_i64, |
| 839 | 852 | .int_big_positive, |
| 840 | 853 | .int_big_negative, |
| 854 | .ref_val, | |
| 841 | 855 | .decl_ref, |
| 842 | 856 | .elem_ptr, |
| 843 | 857 | .bytes, |
| ... | ... | @@ -896,11 +910,16 @@ pub const Value = extern union { |
| 896 | 910 | elem_type: *Type, |
| 897 | 911 | }; |
| 898 | 912 | |
| 913 | /// Represents a pointer to another immutable value. | |
| 914 | pub const RefVal = struct { | |
| 915 | base: Payload = Payload{ .tag = .ref_val }, | |
| 916 | val: Value, | |
| 917 | }; | |
| 918 | ||
| 899 | 919 | /// Represents a pointer to a decl, not the value of the decl. |
| 900 | 920 | pub const DeclRef = struct { |
| 901 | 921 | base: Payload = Payload{ .tag = .decl_ref }, |
| 902 | /// Index into the Module's decls list | |
| 903 | index: usize, | |
| 922 | decl: *ir.Module.Decl, | |
| 904 | 923 | }; |
| 905 | 924 | |
| 906 | 925 | pub const ElemPtr = struct { |