commit ed137d25ef0fb94f2ea0db4f993a0adfcaf63b58 (tree)
parent 1cde0edff469fbe5ee62cb10a44161b4c9910f98
Author: Andrew Kelley <andrew@ziglang.org>
Date: Tue, 19 May 2020 13:56:06 -0400
Merge branch 'stage2-fn-calls'
Diffstat:
4 files changed, 77 insertions(+), 10 deletions(-)
diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig
@@ -231,6 +231,7 @@ pub const Fn = struct {
dependency_failure,
success: Body,
},
+ owner_decl: *Decl,
/// This memory is temporary and points to stack memory for the duration
/// of Fn analysis.
@@ -883,14 +884,6 @@ fn resolveDecl(
};
const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
- const has_codegen_bits = typed_value.ty.hasCodeGenBits();
- if (has_codegen_bits) {
- // We don't fully codegen the decl until later, but we do need to reserve a global
- // offset table index for it. This allows us to codegen decls out of dependency order,
- // increasing how many computations can be done in parallel.
- try self.bin_file.allocateDeclIndexes(new_decl);
- }
-
arena_state.* = decl_scope.arena.state;
new_decl.typed_value = .{
@@ -900,7 +893,12 @@ fn resolveDecl(
},
};
new_decl.analysis = .complete;
- if (has_codegen_bits) {
+ if (typed_value.ty.hasCodeGenBits()) {
+ // We don't fully codegen the decl until later, but we do need to reserve a global
+ // offset table index for it. This allows us to codegen decls out of dependency order,
+ // increasing how many computations can be done in parallel.
+ try self.bin_file.allocateDeclIndexes(new_decl);
+
// We ensureCapacity when scanning for decls.
self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
}
@@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
new_func.* = .{
.fn_type = fn_type,
.analysis = .{ .queued = fn_inst },
+ .owner_decl = scope.decl(),
};
const fn_payload = try scope.arena().create(Value.Payload.Function);
fn_payload.* = .{ .func = new_func };
diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig
@@ -203,7 +203,20 @@ const Function = struct {
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
const func = func_val.func;
- return self.fail(inst.base.src, "TODO implement calling function", .{});
+ const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+ const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
+ // ff 14 25 xx xx xx xx call [addr]
+ try self.code.resize(self.code.items.len + 7);
+ self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
+ mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
+ const return_type = func.fn_type.fnReturnType();
+ switch (return_type.zigTypeTag()) {
+ .Void => return MCValue{ .none = {} },
+ .NoReturn => return MCValue{ .unreach = {} },
+ else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
+ }
} else {
return self.fail(inst.base.src, "TODO implement calling weird function values", .{});
}
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
@@ -740,6 +740,7 @@ pub const ElfFile = struct {
const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);
if (amt != text_size) return error.InputOutput;
shdr.sh_offset = new_offset;
+ phdr.p_offset = new_offset;
}
// Now that we know the code size, we need to update the program header for executable code
shdr.sh_size = needed_size;
@@ -1034,6 +1035,7 @@ pub const ElfFile = struct {
const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
if (amt != shdr.sh_size) return error.InputOutput;
shdr.sh_offset = new_offset;
+ phdr.p_offset = new_offset;
}
shdr.sh_size = needed_size;
phdr.p_memsz = needed_size;
diff --git a/test/stage2/zir.zig b/test/stage2/zir.zig
@@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void {
\\
},
);
+
+ ctx.addZIRCompareOutput(
+ "function call with no args no return value",
+ &[_][]const u8{
+ \\@noreturn = primitive(noreturn)
+ \\@void = primitive(void)
+ \\@usize = primitive(usize)
+ \\@0 = int(0)
+ \\@1 = int(1)
+ \\@2 = int(2)
+ \\@3 = int(3)
+ \\
+ \\@syscall_array = str("syscall")
+ \\@sysoutreg_array = str("={rax}")
+ \\@rax_array = str("{rax}")
+ \\@rdi_array = str("{rdi}")
+ \\@rcx_array = str("rcx")
+ \\@r11_array = str("r11")
+ \\@memory_array = str("memory")
+ \\
+ \\@exit0_fnty = fntype([], @noreturn)
+ \\@exit0 = fn(@exit0_fnty, {
+ \\ %SYS_exit_group = int(231)
+ \\ %exit_code = as(@usize, @0)
+ \\
+ \\ %syscall = ref(@syscall_array)
+ \\ %sysoutreg = ref(@sysoutreg_array)
+ \\ %rax = ref(@rax_array)
+ \\ %rdi = ref(@rdi_array)
+ \\ %rcx = ref(@rcx_array)
+ \\ %r11 = ref(@r11_array)
+ \\ %memory = ref(@memory_array)
+ \\
+ \\ %rc = asm(%syscall, @usize,
+ \\ volatile=1,
+ \\ output=%sysoutreg,
+ \\ inputs=[%rax, %rdi],
+ \\ clobbers=[%rcx, %r11, %memory],
+ \\ args=[%SYS_exit_group, %exit_code])
+ \\
+ \\ %99 = unreachable()
+ \\});
+ \\
+ \\@start_fnty = fntype([], @noreturn, cc=Naked)
+ \\@start = fn(@start_fnty, {
+ \\ %0 = call(@exit0, [])
+ \\})
+ \\@9 = str("_start")
+ \\@10 = ref(@9)
+ \\@11 = export(@10, @start)
+ },
+ &[_][]const u8{""},
+ );
}