authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-28 12:19:00-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-28 12:19:00-04:00
log3eed7a4dea3b66bf236278caba7f96228b13214f
tree81ea8de9e0c2f066f78a2b53c0efa89287bfd4b3
parentc7ca1fe6f7b8796a42de908faeaa6ec24e8eb118

stage2: first pass at recursive dependency resolution


4 files changed, 290 insertions(+), 129 deletions(-)

src-self-hosted/Module.zig+169-40
......@@ -128,6 +128,9 @@ pub const Decl = struct {
128128 /// Completed successfully before; the `typed_value.most_recent` can be accessed, and
129129 /// new semantic analysis is in progress.
130130 repeat_in_progress,
131 /// Failed before; the `typed_value.most_recent` is not available, and
132 /// new semantic analysis is in progress.
133 repeat_in_progress_novalue,
131134 /// Everything is done and updated.
132135 complete,
133136 },
......@@ -136,18 +139,24 @@ pub const Decl = struct {
136139 /// This is populated regardless of semantic analysis and code generation.
137140 link: link.ElfFile.TextBlock = link.ElfFile.TextBlock.empty,
138141
142 contents_hash: Hash,
143
139144 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
140145 /// typed_value is modified.
141146 /// TODO look into using a lightweight map/set data structure rather than a linear array.
142147 dependants: ArrayListUnmanaged(*Decl) = ArrayListUnmanaged(*Decl){},
143
144 contents_hash: Hash,
148 /// The shallow set of other decls whose typed_value changing indicates that this Decl's
149 /// typed_value may need to be regenerated.
150 /// TODO look into using a lightweight map/set data structure rather than a linear array.
151 dependencies: ArrayListUnmanaged(*Decl) = ArrayListUnmanaged(*Decl){},
145152
146153 pub fn destroy(self: *Decl, allocator: *Allocator) void {
147154 allocator.free(mem.spanZ(self.name));
148155 if (self.typedValueManaged()) |tvm| {
149156 tvm.deinit(allocator);
150157 }
158 self.dependants.deinit(allocator);
159 self.dependencies.deinit(allocator);
151160 allocator.destroy(self);
152161 }
153162
......@@ -204,6 +213,7 @@ pub const Decl = struct {
204213 .initial_in_progress,
205214 .initial_dependency_failure,
206215 .initial_sema_failure,
216 .repeat_in_progress_novalue,
207217 => return null,
208218 .codegen_failure,
209219 .codegen_failure_retryable,
......@@ -214,6 +224,31 @@ pub const Decl = struct {
214224 => return &self.typed_value.most_recent,
215225 }
216226 }
227
228 fn flagForRegeneration(self: *Decl) void {
229 if (self.typedValueManaged() == null) {
230 self.analysis = .repeat_in_progress_novalue;
231 } else {
232 self.analysis = .repeat_in_progress;
233 }
234 }
235
236 fn isFlaggedForRegeneration(self: *Decl) bool {
237 return switch (self.analysis) {
238 .repeat_in_progress, .repeat_in_progress_novalue => true,
239 else => false,
240 };
241 }
242
243 fn removeDependant(self: *Decl, other: *Decl) void {
244 for (self.dependants.items) |item, i| {
245 if (item == other) {
246 _ = self.dependants.swapRemove(i);
247 return;
248 }
249 }
250 unreachable;
251 }
217252};
218253
219254/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
......@@ -266,12 +301,12 @@ pub const Scope = struct {
266301
267302 /// Asserts the scope has a parent which is a DeclAnalysis and
268303 /// returns the Decl.
269 pub fn decl(self: *Scope) *Decl {
270 switch (self.tag) {
271 .block => return self.cast(Block).?.decl,
272 .decl => return self.cast(DeclAnalysis).?.decl,
273 .zir_module => unreachable,
274 }
304 pub fn decl(self: *Scope) ?*Decl {
305 return switch (self.tag) {
306 .block => self.cast(Block).?.decl,
307 .decl => self.cast(DeclAnalysis).?.decl,
308 .zir_module => null,
309 };
275310 }
276311
277312 /// Asserts the scope has a parent which is a ZIRModule and
......@@ -517,11 +552,7 @@ pub fn deinit(self: *Module) void {
517552 {
518553 var it = self.export_owners.iterator();
519554 while (it.next()) |kv| {
520 const export_list = kv.value;
521 for (export_list) |exp| {
522 allocator.destroy(exp);
523 }
524 allocator.free(export_list);
555 freeExportList(allocator, kv.value);
525556 }
526557 self.export_owners.deinit();
527558 }
......@@ -532,6 +563,13 @@ pub fn deinit(self: *Module) void {
532563 self.* = undefined;
533564}
534565
566fn freeExportList(allocator: *Allocator, export_list: []*Export) void {
567 for (export_list) |exp| {
568 allocator.destroy(exp);
569 }
570 allocator.free(export_list);
571}
572
535573pub fn target(self: Module) std.Target {
536574 return self.bin_file.options.target;
537575}
......@@ -634,9 +672,9 @@ const InnerError = error{ OutOfMemory, AnalysisFail };
634672pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
635673 while (self.work_queue.readItem()) |work_item| switch (work_item) {
636674 .codegen_decl => |decl| switch (decl.analysis) {
637 .initial_in_progress,
638 .repeat_in_progress,
639 => unreachable,
675 .initial_in_progress => unreachable,
676 .repeat_in_progress => unreachable,
677 .repeat_in_progress_novalue => unreachable,
640678
641679 .initial_sema_failure,
642680 .repeat_sema_failure,
......@@ -686,6 +724,23 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
686724 };
687725}
688726
727fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
728 try depender.dependencies.ensureCapacity(self.allocator, depender.dependencies.items.len + 1);
729 try dependee.dependants.ensureCapacity(self.allocator, dependee.dependants.items.len + 1);
730
731 for (depender.dependencies.items) |item| {
732 if (item == dependee) break; // Already in the set.
733 } else {
734 depender.dependencies.appendAssumeCapacity(dependee);
735 }
736
737 for (dependee.dependants.items) |item| {
738 if (item == depender) break; // Already in the set.
739 } else {
740 dependee.dependants.appendAssumeCapacity(depender);
741 }
742}
743
689744fn getSource(self: *Module, root_scope: *Scope.ZIRModule) ![:0]const u8 {
690745 switch (root_scope.source) {
691746 .unloaded => {
......@@ -772,37 +827,105 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
772827 => {
773828 const src_module = try self.getSrcModule(root_scope);
774829
775 // Look for changed decls.
830 // Look for changed decls. First we add all the decls that changed
831 // into the set.
832 var regen_decl_set = std.ArrayList(*Decl).init(self.allocator);
833 defer regen_decl_set.deinit();
834 try regen_decl_set.ensureCapacity(src_module.decls.len);
835
836 var exports_to_resolve = std.ArrayList(*zir.Inst).init(self.allocator);
837 defer exports_to_resolve.deinit();
838
776839 for (src_module.decls) |src_decl| {
777840 const name_hash = Decl.hashSimpleName(src_decl.name);
778841 if (self.decl_table.get(name_hash)) |kv| {
779842 const decl = kv.value;
780843 const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
781844 if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {
782 // TODO recursive dependency management
783 //std.debug.warn("noticed that '{}' changed\n", .{src_decl.name});
784 self.decl_table.removeAssertDiscard(name_hash);
785 const saved_link = decl.link;
786 decl.destroy(self.allocator);
787 if (self.export_owners.getValue(decl)) |exports| {
788 @panic("TODO handle updating a decl that does an export");
789 }
790 const new_decl = self.resolveDecl(
791 &root_scope.base,
792 src_decl,
793 saved_link,
794 ) catch |err| switch (err) {
795 error.OutOfMemory => return error.OutOfMemory,
796 error.AnalysisFail => continue,
797 };
798 if (self.decl_exports.remove(decl)) |entry| {
799 self.decl_exports.putAssumeCapacityNoClobber(new_decl, entry.value);
800 }
845 std.debug.warn("noticed that '{}' changed\n", .{src_decl.name});
846 regen_decl_set.appendAssumeCapacity(decl);
801847 }
802848 } else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
803 _ = try self.resolveDecl(&root_scope.base, &export_inst.base, link.ElfFile.TextBlock.empty);
849 try exports_to_resolve.append(&export_inst.base);
804850 }
805851 }
852
853 // Next, recursively chase the dependency graph, to populate the set.
854 {
855 var i: usize = 0;
856 while (i < regen_decl_set.items.len) : (i += 1) {
857 const decl = regen_decl_set.items[i];
858 if (decl.isFlaggedForRegeneration()) {
859 // We already looked at this decl's dependency graph.
860 continue;
861 }
862 decl.flagForRegeneration();
863 // Remove itself from its dependencies, because we are about to destroy the
864 // decl pointer.
865 for (decl.dependencies.items) |dep| {
866 dep.removeDependant(decl);
867 }
868 // Populate the set with decls that need to get regenerated because they
869 // depend on this one.
870 // TODO If it is only a function body that is modified, it should break the chain
871 // and not cause its dependants to be regenerated.
872 for (decl.dependants.items) |dep| {
873 if (!dep.isFlaggedForRegeneration()) {
874 regen_decl_set.appendAssumeCapacity(dep);
875 }
876 }
877 }
878 }
879
880 // Remove them all from the decl_table.
881 for (regen_decl_set.items) |decl| {
882 const decl_name = mem.spanZ(decl.name);
883 const old_name_hash = Decl.hashSimpleName(decl_name);
884 self.decl_table.removeAssertDiscard(old_name_hash);
885
886 if (self.export_owners.remove(decl)) |kv| {
887 for (kv.value) |exp| {
888 self.bin_file.deleteExport(exp.link);
889 }
890 freeExportList(self.allocator, kv.value);
891 }
892 }
893
894 // Regenerate the decls in the set.
895 const zir_module = try self.getSrcModule(root_scope);
896
897 while (regen_decl_set.popOrNull()) |decl| {
898 const decl_name = mem.spanZ(decl.name);
899 std.debug.warn("regenerating {}\n", .{decl_name});
900 const saved_link = decl.link;
901 const decl_exports_entry = if (self.decl_exports.remove(decl)) |kv| kv.value else null;
902 const src_decl = zir_module.findDecl(decl_name) orelse {
903 @panic("TODO treat this as a deleted decl");
904 };
905
906 decl.destroy(self.allocator);
907
908 const new_decl = self.resolveDecl(
909 &root_scope.base,
910 src_decl,
911 saved_link,
912 ) catch |err| switch (err) {
913 error.OutOfMemory => return error.OutOfMemory,
914 error.AnalysisFail => continue,
915 };
916 if (decl_exports_entry) |entry| {
917 const gop = try self.decl_exports.getOrPut(new_decl);
918 if (gop.found_existing) {
919 self.allocator.free(entry);
920 } else {
921 gop.kv.value = entry;
922 }
923 }
924 }
925
926 for (exports_to_resolve.items) |export_inst| {
927 _ = try self.resolveDecl(&root_scope.base, export_inst, link.ElfFile.TextBlock.empty);
928 }
806929 },
807930 }
808931}
......@@ -906,11 +1029,13 @@ fn resolveDecl(
9061029 }
9071030}
9081031
1032/// Declares a dependency on the decl.
9091033fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
9101034 const decl = try self.resolveDecl(scope, old_inst, link.ElfFile.TextBlock.empty);
9111035 switch (decl.analysis) {
9121036 .initial_in_progress => unreachable,
9131037 .repeat_in_progress => unreachable,
1038 .repeat_in_progress_novalue => unreachable,
9141039 .initial_dependency_failure,
9151040 .repeat_dependency_failure,
9161041 .initial_sema_failure,
......@@ -919,8 +1044,12 @@ fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerE
9191044 .codegen_failure_retryable,
9201045 => return error.AnalysisFail,
9211046
922 .complete => return decl,
1047 .complete => {},
1048 }
1049 if (scope.decl()) |scope_decl| {
1050 try self.declareDeclDependency(scope_decl, decl);
9231051 }
1052 return decl;
9241053}
9251054
9261055fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
......@@ -998,7 +1127,7 @@ fn analyzeExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) In
9981127 const new_export = try self.allocator.create(Export);
9991128 errdefer self.allocator.destroy(new_export);
10001129
1001 const owner_decl = scope.decl();
1130 const owner_decl = scope.decl().?;
10021131
10031132 new_export.* = .{
10041133 .options = .{ .name = symbol_name },
......@@ -1327,7 +1456,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
13271456 new_func.* = .{
13281457 .fn_type = fn_type,
13291458 .analysis = .{ .queued = fn_inst },
1330 .owner_decl = scope.decl(),
1459 .owner_decl = scope.decl().?,
13311460 };
13321461 const fn_payload = try scope.arena().create(Value.Payload.Function);
13331462 fn_payload.* = .{ .func = new_func };
src-self-hosted/link.zig+40-18
......@@ -126,6 +126,8 @@ pub const ElfFile = struct {
126126 local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){},
127127 global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){},
128128
129 global_symbol_free_list: std.ArrayListUnmanaged(usize) = std.ArrayListUnmanaged(usize){},
130
129131 /// Same order as in the file. The value is the absolute vaddr value.
130132 /// If the vaddr of the executable program header changes, the entire
131133 /// offset table needs to be rewritten.
......@@ -153,7 +155,7 @@ pub const ElfFile = struct {
153155 /// overcapacity can be negative. A simple way to have negative overcapacity is to
154156 /// allocate a fresh text block, which will have ideal capacity, and then grow it
155157 /// by 1 byte. It will then have -1 overcapacity.
156 free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){},
158 text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){},
157159 last_text_block: ?*TextBlock = null,
158160
159161 /// `alloc_num / alloc_den` is the factor of padding when allocating.
......@@ -229,6 +231,8 @@ pub const ElfFile = struct {
229231 self.shstrtab.deinit(self.allocator);
230232 self.local_symbols.deinit(self.allocator);
231233 self.global_symbols.deinit(self.allocator);
234 self.global_symbol_free_list.deinit(self.allocator);
235 self.text_block_free_list.deinit(self.allocator);
232236 self.offset_table.deinit(self.allocator);
233237 if (self.owns_file_handle) {
234238 if (self.file) |f| f.close();
......@@ -775,12 +779,12 @@ pub const ElfFile = struct {
775779 var already_have_free_list_node = false;
776780 {
777781 var i: usize = 0;
778 while (i < self.free_list.items.len) {
779 if (self.free_list.items[i] == text_block) {
780 _ = self.free_list.swapRemove(i);
782 while (i < self.text_block_free_list.items.len) {
783 if (self.text_block_free_list.items[i] == text_block) {
784 _ = self.text_block_free_list.swapRemove(i);
781785 continue;
782786 }
783 if (self.free_list.items[i] == text_block.prev) {
787 if (self.text_block_free_list.items[i] == text_block.prev) {
784788 already_have_free_list_node = true;
785789 }
786790 i += 1;
......@@ -797,7 +801,7 @@ pub const ElfFile = struct {
797801 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
798802 // The free list is heuristics, it doesn't have to be perfect, so we can
799803 // ignore the OOM here.
800 self.free_list.append(self.allocator, prev) catch {};
804 self.text_block_free_list.append(self.allocator, prev) catch {};
801805 }
802806 } else {
803807 text_block.prev = null;
......@@ -840,8 +844,8 @@ pub const ElfFile = struct {
840844 // The list is unordered. We'll just take the first thing that works.
841845 const vaddr = blk: {
842846 var i: usize = 0;
843 while (i < self.free_list.items.len) {
844 const big_block = self.free_list.items[i];
847 while (i < self.text_block_free_list.items.len) {
848 const big_block = self.text_block_free_list.items[i];
845849 // We now have a pointer to a live text block that has too much capacity.
846850 // Is it enough that we could fit this new text block?
847851 const sym = self.local_symbols.items[big_block.local_sym_index];
......@@ -856,7 +860,7 @@ pub const ElfFile = struct {
856860 // should be deleted because the block that it points to has grown to take up
857861 // more of the extra capacity.
858862 if (!big_block.freeListEligible(self.*)) {
859 _ = self.free_list.swapRemove(i);
863 _ = self.text_block_free_list.swapRemove(i);
860864 } else {
861865 i += 1;
862866 }
......@@ -932,7 +936,7 @@ pub const ElfFile = struct {
932936 text_block.next = null;
933937 }
934938 if (free_list_removal) |i| {
935 _ = self.free_list.swapRemove(i);
939 _ = self.text_block_free_list.swapRemove(i);
936940 }
937941 return vaddr;
938942 }
......@@ -958,11 +962,18 @@ pub const ElfFile = struct {
958962
959963 self.offset_table_count_dirty = true;
960964
961 //std.debug.warn("allocating symbol index {}\n", .{local_sym_index});
965 std.debug.warn("allocating symbol index {} for {}\n", .{local_sym_index, decl.name});
962966 decl.link.local_sym_index = @intCast(u32, local_sym_index);
963967 decl.link.offset_table_index = @intCast(u32, offset_table_index);
964968 }
965969
970 pub fn freeDecl(self: *ElfFile, decl: *Module.Decl) void {
971 self.freeTextBlock(&decl.link);
972 if (decl.link.local_sym_index != 0) {
973 @panic("TODO free the symbol entry and offset table entry");
974 }
975 }
976
966977 pub fn updateDecl(self: *ElfFile, module: *Module, decl: *Module.Decl) !void {
967978 var code_buffer = std.ArrayList(u8).init(self.allocator);
968979 defer code_buffer.deinit();
......@@ -993,11 +1004,11 @@ pub const ElfFile = struct {
9931004 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
9941005 if (need_realloc) {
9951006 const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
996 //std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
1007 std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
9971008 if (vaddr != local_sym.st_value) {
9981009 local_sym.st_value = vaddr;
9991010
1000 //std.debug.warn(" (writing new offset table entry)\n", .{});
1011 std.debug.warn(" (writing new offset table entry)\n", .{});
10011012 self.offset_table.items[decl.link.offset_table_index] = vaddr;
10021013 try self.writeOffsetTableEntry(decl.link.offset_table_index);
10031014 }
......@@ -1015,7 +1026,7 @@ pub const ElfFile = struct {
10151026 const decl_name = mem.spanZ(decl.name);
10161027 const name_str_index = try self.makeString(decl_name);
10171028 const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
1018 //std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
1029 std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
10191030 errdefer self.freeTextBlock(&decl.link);
10201031
10211032 local_sym.* = .{
......@@ -1048,7 +1059,10 @@ pub const ElfFile = struct {
10481059 decl: *const Module.Decl,
10491060 exports: []const *Module.Export,
10501061 ) !void {
1062 // In addition to ensuring capacity for global_symbols, we also ensure capacity for freeing all of
1063 // them, so that deleting exports is guaranteed to succeed.
10511064 try self.global_symbols.ensureCapacity(self.allocator, self.global_symbols.items.len + exports.len);
1065 try self.global_symbol_free_list.ensureCapacity(self.allocator, self.global_symbols.items.len);
10521066 const typed_value = decl.typed_value.most_recent.typed_value;
10531067 if (decl.link.local_sym_index == 0) return;
10541068 const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
......@@ -1095,22 +1109,30 @@ pub const ElfFile = struct {
10951109 };
10961110 } else {
10971111 const name = try self.makeString(exp.options.name);
1098 const i = self.global_symbols.items.len;
1099 self.global_symbols.appendAssumeCapacity(.{
1112 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
1113 _ = self.global_symbols.addOneAssumeCapacity();
1114 break :blk self.global_symbols.items.len - 1;
1115 };
1116 self.global_symbols.items[i] = .{
11001117 .st_name = name,
11011118 .st_info = (stb_bits << 4) | stt_bits,
11021119 .st_other = 0,
11031120 .st_shndx = self.text_section_index.?,
11041121 .st_value = decl_sym.st_value,
11051122 .st_size = decl_sym.st_size,
1106 });
1107 errdefer self.global_symbols.shrink(self.allocator, self.global_symbols.items.len - 1);
1123 };
11081124
11091125 exp.link.sym_index = @intCast(u32, i);
11101126 }
11111127 }
11121128 }
11131129
1130 pub fn deleteExport(self: *ElfFile, exp: Export) void {
1131 const sym_index = exp.sym_index orelse return;
1132 self.global_symbol_free_list.appendAssumeCapacity(sym_index);
1133 self.global_symbols.items[sym_index].st_info = 0;
1134 }
1135
11141136 fn writeProgHeader(self: *ElfFile, index: usize) !void {
11151137 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
11161138 const offset = self.program_headers.items[index].p_offset;
src-self-hosted/zir.zig+10
......@@ -442,6 +442,16 @@ pub const Module = struct {
442442
443443 const InstPtrTable = std.AutoHashMap(*Inst, struct { index: usize, fn_body: ?*Module.Body });
444444
445 /// TODO Look into making a table to speed this up.
446 pub fn findDecl(self: Module, name: []const u8) ?*Inst {
447 for (self.decls) |decl| {
448 if (mem.eql(u8, decl.name, name)) {
449 return decl;
450 }
451 }
452 return null;
453 }
454
445455 /// The allocator is used for temporary storage, but this function always returns
446456 /// with no resources allocated.
447457 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {
test/stage2/zir.zig+71-71
......@@ -200,73 +200,73 @@ pub fn addCases(ctx: *TestContext) void {
200200 \\@9 = str("_start")
201201 \\@10 = ref(@9)
202202 \\@11 = export(@10, @start)
203// ,
204// \\@noreturn = primitive(noreturn)
205// \\@void = primitive(void)
206// \\@usize = primitive(usize)
207// \\@0 = int(0)
208// \\@1 = int(1)
209// \\@2 = int(2)
210// \\@3 = int(3)
211// \\
212// \\@syscall_array = str("syscall")
213// \\@sysoutreg_array = str("={rax}")
214// \\@rax_array = str("{rax}")
215// \\@rdi_array = str("{rdi}")
216// \\@rcx_array = str("rcx")
217// \\@r11_array = str("r11")
218// \\@rdx_array = str("{rdx}")
219// \\@rsi_array = str("{rsi}")
220// \\@memory_array = str("memory")
221// \\@len_array = str("len")
222// \\
223// \\@msg = str("Hello, world!\n")
224// \\@msg2 = str("Editing the same msg2 decl but this time with a much longer message which will\ncause the data to need to be relocated in virtual address space.\n")
225// \\
226// \\@start_fnty = fntype([], @noreturn, cc=Naked)
227// \\@start = fn(@start_fnty, {
228// \\ %SYS_exit_group = int(231)
229// \\ %exit_code = as(@usize, @0)
230// \\
231// \\ %syscall = ref(@syscall_array)
232// \\ %sysoutreg = ref(@sysoutreg_array)
233// \\ %rax = ref(@rax_array)
234// \\ %rdi = ref(@rdi_array)
235// \\ %rcx = ref(@rcx_array)
236// \\ %rdx = ref(@rdx_array)
237// \\ %rsi = ref(@rsi_array)
238// \\ %r11 = ref(@r11_array)
239// \\ %memory = ref(@memory_array)
240// \\
241// \\ %SYS_write = as(@usize, @1)
242// \\ %STDOUT_FILENO = as(@usize, @1)
243// \\
244// \\ %msg_ptr = ref(@msg2)
245// \\ %msg_addr = ptrtoint(%msg_ptr)
246// \\
247// \\ %len_name = ref(@len_array)
248// \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
249// \\ %msg_len = deref(%msg_len_ptr)
250// \\ %rc_write = asm(%syscall, @usize,
251// \\ volatile=1,
252// \\ output=%sysoutreg,
253// \\ inputs=[%rax, %rdi, %rsi, %rdx],
254// \\ clobbers=[%rcx, %r11, %memory],
255// \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
256// \\
257// \\ %rc_exit = asm(%syscall, @usize,
258// \\ volatile=1,
259// \\ output=%sysoutreg,
260// \\ inputs=[%rax, %rdi],
261// \\ clobbers=[%rcx, %r11, %memory],
262// \\ args=[%SYS_exit_group, %exit_code])
263// \\
264// \\ %99 = unreachable()
265// \\});
266// \\
267// \\@9 = str("_start")
268// \\@10 = ref(@9)
269// \\@11 = export(@10, @start)
203 ,
204 \\@noreturn = primitive(noreturn)
205 \\@void = primitive(void)
206 \\@usize = primitive(usize)
207 \\@0 = int(0)
208 \\@1 = int(1)
209 \\@2 = int(2)
210 \\@3 = int(3)
211 \\
212 \\@syscall_array = str("syscall")
213 \\@sysoutreg_array = str("={rax}")
214 \\@rax_array = str("{rax}")
215 \\@rdi_array = str("{rdi}")
216 \\@rcx_array = str("rcx")
217 \\@r11_array = str("r11")
218 \\@rdx_array = str("{rdx}")
219 \\@rsi_array = str("{rsi}")
220 \\@memory_array = str("memory")
221 \\@len_array = str("len")
222 \\
223 \\@msg = str("Hello, world!\n")
224 \\@msg2 = str("Editing the same msg2 decl but this time with a much longer message which will\ncause the data to need to be relocated in virtual address space.\n")
225 \\
226 \\@start_fnty = fntype([], @noreturn, cc=Naked)
227 \\@start = fn(@start_fnty, {
228 \\ %SYS_exit_group = int(231)
229 \\ %exit_code = as(@usize, @0)
230 \\
231 \\ %syscall = ref(@syscall_array)
232 \\ %sysoutreg = ref(@sysoutreg_array)
233 \\ %rax = ref(@rax_array)
234 \\ %rdi = ref(@rdi_array)
235 \\ %rcx = ref(@rcx_array)
236 \\ %rdx = ref(@rdx_array)
237 \\ %rsi = ref(@rsi_array)
238 \\ %r11 = ref(@r11_array)
239 \\ %memory = ref(@memory_array)
240 \\
241 \\ %SYS_write = as(@usize, @1)
242 \\ %STDOUT_FILENO = as(@usize, @1)
243 \\
244 \\ %msg_ptr = ref(@msg2)
245 \\ %msg_addr = ptrtoint(%msg_ptr)
246 \\
247 \\ %len_name = ref(@len_array)
248 \\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
249 \\ %msg_len = deref(%msg_len_ptr)
250 \\ %rc_write = asm(%syscall, @usize,
251 \\ volatile=1,
252 \\ output=%sysoutreg,
253 \\ inputs=[%rax, %rdi, %rsi, %rdx],
254 \\ clobbers=[%rcx, %r11, %memory],
255 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
256 \\
257 \\ %rc_exit = asm(%syscall, @usize,
258 \\ volatile=1,
259 \\ output=%sysoutreg,
260 \\ inputs=[%rax, %rdi],
261 \\ clobbers=[%rcx, %r11, %memory],
262 \\ args=[%SYS_exit_group, %exit_code])
263 \\
264 \\ %99 = unreachable()
265 \\});
266 \\
267 \\@9 = str("_start")
268 \\@10 = ref(@9)
269 \\@11 = export(@10, @start)
270270 },
271271 &[_][]const u8{
272272 \\Hello, world!
......@@ -274,10 +274,10 @@ pub fn addCases(ctx: *TestContext) void {
274274 ,
275275 \\HELL WORLD
276276 \\
277// ,
278// \\Editing the same msg2 decl but this time with a much longer message which will
279// \\cause the data to need to be relocated in virtual address space.
280// \\
277 ,
278 \\Editing the same msg2 decl but this time with a much longer message which will
279 \\cause the data to need to be relocated in virtual address space.
280 \\
281281 },
282282 );
283283