authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 13:56:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 13:56:06-04:00
loged137d25ef0fb94f2ea0db4f993a0adfcaf63b58
tree089289335a3e6374c88ccb54c5879806132503a6
parent1cde0edff469fbe5ee62cb10a44161b4c9910f98
parent8d3cca7fc2e7b34486cc56951bb0dadb75e498a0

Merge branch 'stage2-fn-calls'


4 files changed, 77 insertions(+), 10 deletions(-)

src-self-hosted/Module.zig+8-9
...@@ -231,6 +231,7 @@ pub const Fn = struct {...@@ -231,6 +231,7 @@ pub const Fn = struct {
231 dependency_failure,231 dependency_failure,
232 success: Body,232 success: Body,
233 },233 },
234 owner_decl: *Decl,
234235
235 /// This memory is temporary and points to stack memory for the duration236 /// This memory is temporary and points to stack memory for the duration
236 /// of Fn analysis.237 /// of Fn analysis.
...@@ -883,14 +884,6 @@ fn resolveDecl(...@@ -883,14 +884,6 @@ fn resolveDecl(
883 };884 };
884 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);885 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
885886
886 const has_codegen_bits = typed_value.ty.hasCodeGenBits();
887 if (has_codegen_bits) {
888 // We don't fully codegen the decl until later, but we do need to reserve a global
889 // offset table index for it. This allows us to codegen decls out of dependency order,
890 // increasing how many computations can be done in parallel.
891 try self.bin_file.allocateDeclIndexes(new_decl);
892 }
893
894 arena_state.* = decl_scope.arena.state;887 arena_state.* = decl_scope.arena.state;
895888
896 new_decl.typed_value = .{889 new_decl.typed_value = .{
...@@ -900,7 +893,12 @@ fn resolveDecl(...@@ -900,7 +893,12 @@ fn resolveDecl(
900 },893 },
901 };894 };
902 new_decl.analysis = .complete;895 new_decl.analysis = .complete;
903 if (has_codegen_bits) {896 if (typed_value.ty.hasCodeGenBits()) {
897 // We don't fully codegen the decl until later, but we do need to reserve a global
898 // offset table index for it. This allows us to codegen decls out of dependency order,
899 // increasing how many computations can be done in parallel.
900 try self.bin_file.allocateDeclIndexes(new_decl);
901
904 // We ensureCapacity when scanning for decls.902 // We ensureCapacity when scanning for decls.
905 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });903 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
906 }904 }
...@@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError...@@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
1329 new_func.* = .{1327 new_func.* = .{
1330 .fn_type = fn_type,1328 .fn_type = fn_type,
1331 .analysis = .{ .queued = fn_inst },1329 .analysis = .{ .queued = fn_inst },
1330 .owner_decl = scope.decl(),
1332 };1331 };
1333 const fn_payload = try scope.arena().create(Value.Payload.Function);1332 const fn_payload = try scope.arena().create(Value.Payload.Function);
1334 fn_payload.* = .{ .func = new_func };1333 fn_payload.* = .{ .func = new_func };
src-self-hosted/codegen.zig+14-1
...@@ -203,7 +203,20 @@ const Function = struct {...@@ -203,7 +203,20 @@ const Function = struct {
203203
204 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {204 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
205 const func = func_val.func;205 const func = func_val.func;
206 return self.fail(inst.base.src, "TODO implement calling function", .{});206 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
207 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
208 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
209 const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
210 // ff 14 25 xx xx xx xx call [addr]
211 try self.code.resize(self.code.items.len + 7);
212 self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
213 mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
214 const return_type = func.fn_type.fnReturnType();
215 switch (return_type.zigTypeTag()) {
216 .Void => return MCValue{ .none = {} },
217 .NoReturn => return MCValue{ .unreach = {} },
218 else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
219 }
207 } else {220 } else {
208 return self.fail(inst.base.src, "TODO implement calling weird function values", .{});221 return self.fail(inst.base.src, "TODO implement calling weird function values", .{});
209 }222 }
src-self-hosted/link.zig+2
...@@ -740,6 +740,7 @@ pub const ElfFile = struct {...@@ -740,6 +740,7 @@ pub const ElfFile = struct {
740 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);740 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);
741 if (amt != text_size) return error.InputOutput;741 if (amt != text_size) return error.InputOutput;
742 shdr.sh_offset = new_offset;742 shdr.sh_offset = new_offset;
743 phdr.p_offset = new_offset;
743 }744 }
744 // Now that we know the code size, we need to update the program header for executable code745 // Now that we know the code size, we need to update the program header for executable code
745 shdr.sh_size = needed_size;746 shdr.sh_size = needed_size;
...@@ -1034,6 +1035,7 @@ pub const ElfFile = struct {...@@ -1034,6 +1035,7 @@ pub const ElfFile = struct {
1034 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);1035 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
1035 if (amt != shdr.sh_size) return error.InputOutput;1036 if (amt != shdr.sh_size) return error.InputOutput;
1036 shdr.sh_offset = new_offset;1037 shdr.sh_offset = new_offset;
1038 phdr.p_offset = new_offset;
1037 }1039 }
1038 shdr.sh_size = needed_size;1040 shdr.sh_size = needed_size;
1039 phdr.p_memsz = needed_size;1041 phdr.p_memsz = needed_size;
test/stage2/zir.zig+53
...@@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void {...@@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void {
209 \\209 \\
210 },210 },
211 );211 );
212
213 ctx.addZIRCompareOutput(
214 "function call with no args no return value",
215 &[_][]const u8{
216 \\@noreturn = primitive(noreturn)
217 \\@void = primitive(void)
218 \\@usize = primitive(usize)
219 \\@0 = int(0)
220 \\@1 = int(1)
221 \\@2 = int(2)
222 \\@3 = int(3)
223 \\
224 \\@syscall_array = str("syscall")
225 \\@sysoutreg_array = str("={rax}")
226 \\@rax_array = str("{rax}")
227 \\@rdi_array = str("{rdi}")
228 \\@rcx_array = str("rcx")
229 \\@r11_array = str("r11")
230 \\@memory_array = str("memory")
231 \\
232 \\@exit0_fnty = fntype([], @noreturn)
233 \\@exit0 = fn(@exit0_fnty, {
234 \\ %SYS_exit_group = int(231)
235 \\ %exit_code = as(@usize, @0)
236 \\
237 \\ %syscall = ref(@syscall_array)
238 \\ %sysoutreg = ref(@sysoutreg_array)
239 \\ %rax = ref(@rax_array)
240 \\ %rdi = ref(@rdi_array)
241 \\ %rcx = ref(@rcx_array)
242 \\ %r11 = ref(@r11_array)
243 \\ %memory = ref(@memory_array)
244 \\
245 \\ %rc = asm(%syscall, @usize,
246 \\ volatile=1,
247 \\ output=%sysoutreg,
248 \\ inputs=[%rax, %rdi],
249 \\ clobbers=[%rcx, %r11, %memory],
250 \\ args=[%SYS_exit_group, %exit_code])
251 \\
252 \\ %99 = unreachable()
253 \\});
254 \\
255 \\@start_fnty = fntype([], @noreturn, cc=Naked)
256 \\@start = fn(@start_fnty, {
257 \\ %0 = call(@exit0, [])
258 \\})
259 \\@9 = str("_start")
260 \\@10 = ref(@9)
261 \\@11 = export(@10, @start)
262 },
263 &[_][]const u8{""},
264 );
212}265}