Merge branch 'stage2-fn-calls'

This commit is contained in:
Andrew Kelley
2020-05-19 13:56:06 -04:00
4 changed files with 77 additions and 10 deletions

View File

@@ -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 };

View File

@@ -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", .{});
}

View File

@@ -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;

View File

@@ -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{""},
);
}